kerykeion 5.0.0a9__py3-none-any.whl → 5.1.8__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.

Files changed (79) hide show
  1. kerykeion/__init__.py +50 -9
  2. kerykeion/aspects/__init__.py +5 -2
  3. kerykeion/aspects/aspects_factory.py +568 -0
  4. kerykeion/aspects/aspects_utils.py +78 -11
  5. kerykeion/astrological_subject_factory.py +1032 -275
  6. kerykeion/backword.py +820 -0
  7. kerykeion/chart_data_factory.py +552 -0
  8. kerykeion/charts/chart_drawer.py +2661 -0
  9. kerykeion/charts/charts_utils.py +652 -399
  10. kerykeion/charts/draw_planets.py +603 -353
  11. kerykeion/charts/templates/aspect_grid_only.xml +326 -198
  12. kerykeion/charts/templates/chart.xml +306 -256
  13. kerykeion/charts/templates/wheel_only.xml +330 -200
  14. kerykeion/charts/themes/black-and-white.css +148 -0
  15. kerykeion/charts/themes/classic.css +11 -0
  16. kerykeion/charts/themes/dark-high-contrast.css +11 -0
  17. kerykeion/charts/themes/dark.css +11 -0
  18. kerykeion/charts/themes/light.css +11 -0
  19. kerykeion/charts/themes/strawberry.css +10 -0
  20. kerykeion/composite_subject_factory.py +232 -13
  21. kerykeion/ephemeris_data_factory.py +443 -0
  22. kerykeion/fetch_geonames.py +78 -21
  23. kerykeion/house_comparison/__init__.py +4 -1
  24. kerykeion/house_comparison/house_comparison_factory.py +52 -19
  25. kerykeion/house_comparison/house_comparison_utils.py +37 -9
  26. kerykeion/kr_types/__init__.py +66 -6
  27. kerykeion/kr_types/chart_template_model.py +20 -0
  28. kerykeion/kr_types/kerykeion_exception.py +15 -9
  29. kerykeion/kr_types/kr_literals.py +14 -160
  30. kerykeion/kr_types/kr_models.py +14 -291
  31. kerykeion/kr_types/settings_models.py +15 -167
  32. kerykeion/planetary_return_factory.py +545 -40
  33. kerykeion/relationship_score_factory.py +137 -63
  34. kerykeion/report.py +749 -64
  35. kerykeion/schemas/__init__.py +106 -0
  36. kerykeion/schemas/chart_template_model.py +367 -0
  37. kerykeion/schemas/kerykeion_exception.py +20 -0
  38. kerykeion/schemas/kr_literals.py +181 -0
  39. kerykeion/schemas/kr_models.py +603 -0
  40. kerykeion/schemas/settings_models.py +188 -0
  41. kerykeion/settings/__init__.py +20 -1
  42. kerykeion/settings/chart_defaults.py +444 -0
  43. kerykeion/settings/config_constants.py +88 -12
  44. kerykeion/settings/kerykeion_settings.py +32 -75
  45. kerykeion/settings/translation_strings.py +1499 -0
  46. kerykeion/settings/translations.py +74 -0
  47. kerykeion/sweph/ast136/s136108s.se1 +0 -0
  48. kerykeion/sweph/ast136/s136199s.se1 +0 -0
  49. kerykeion/sweph/ast136/s136472s.se1 +0 -0
  50. kerykeion/sweph/ast28/se28978s.se1 +0 -0
  51. kerykeion/sweph/ast50/se50000s.se1 +0 -0
  52. kerykeion/sweph/ast90/se90377s.se1 +0 -0
  53. kerykeion/sweph/ast90/se90482s.se1 +0 -0
  54. kerykeion/sweph/sefstars.txt +1602 -0
  55. kerykeion/transits_time_range_factory.py +302 -0
  56. kerykeion/utilities.py +289 -204
  57. kerykeion-5.1.8.dist-info/METADATA +1793 -0
  58. kerykeion-5.1.8.dist-info/RECORD +63 -0
  59. kerykeion/aspects/natal_aspects.py +0 -181
  60. kerykeion/aspects/synastry_aspects.py +0 -141
  61. kerykeion/aspects/transits_time_range.py +0 -41
  62. kerykeion/charts/draw_planets_v2.py +0 -649
  63. kerykeion/charts/draw_planets_v3.py +0 -679
  64. kerykeion/charts/kerykeion_chart_svg.py +0 -2038
  65. kerykeion/enums.py +0 -57
  66. kerykeion/ephemeris_data.py +0 -238
  67. kerykeion/house_comparison/house_comparison_models.py +0 -38
  68. kerykeion/kr_types/chart_types.py +0 -106
  69. kerykeion/settings/kr.config.json +0 -1304
  70. kerykeion/settings/legacy/__init__.py +0 -0
  71. kerykeion/settings/legacy/legacy_celestial_points_settings.py +0 -299
  72. kerykeion/settings/legacy/legacy_chart_aspects_settings.py +0 -71
  73. kerykeion/settings/legacy/legacy_color_settings.py +0 -42
  74. kerykeion/transits_time_range.py +0 -128
  75. kerykeion-5.0.0a9.dist-info/METADATA +0 -636
  76. kerykeion-5.0.0a9.dist-info/RECORD +0 -55
  77. kerykeion-5.0.0a9.dist-info/entry_points.txt +0 -2
  78. {kerykeion-5.0.0a9.dist-info → kerykeion-5.1.8.dist-info}/WHEEL +0 -0
  79. {kerykeion-5.0.0a9.dist-info → kerykeion-5.1.8.dist-info}/licenses/LICENSE +0 -0
@@ -1,34 +1,89 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
- This is part of Kerykeion (C) 2025 Giacomo Battaglia
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
4
42
  """
5
43
 
6
- from kerykeion import AstrologicalSubjectFactory
7
- from kerykeion.aspects.synastry_aspects import SynastryAspects
8
44
  import logging
9
- from pathlib import Path
10
- from typing import Union
11
- from kerykeion.kr_types.kr_models import AstrologicalSubjectModel, RelationshipScoreAspectModel, RelationshipScoreModel
12
- from kerykeion.kr_types.kr_literals import RelationshipScoreDescription
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
13
61
 
14
62
 
15
63
  class RelationshipScoreFactory:
16
64
  """
17
- Calculates the relevance of the relationship between two subjects using the Ciro Discepolo method.
65
+ Calculates relationship scores between two subjects using the Ciro Discepolo method.
18
66
 
19
- Results:
20
- - 0 to 5: Minimal relationship
21
- - 5 to 10: Medium relationship
22
- - 10 to 15: Important relationship
23
- - 15 to 20: Very important relationship
24
- - 20 to 35: Exceptional relationship
25
- - 30 and above: Rare Exceptional relationship
67
+ The scoring system evaluates synastry aspects between planetary positions to generate
68
+ numerical compatibility scores with categorical descriptions.
26
69
 
27
- Documentation: http://www.cirodiscepolo.it/Articoli/Discepoloele.htm
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
28
77
 
29
78
  Args:
30
- first_subject (AstrologicalSubjectModel): First subject instance
31
- second_subject (AstrologicalSubjectModel): Second subject instance
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
32
87
  """
33
88
 
34
89
  SCORE_MAPPING = [
@@ -47,6 +102,8 @@ class RelationshipScoreFactory:
47
102
  first_subject: AstrologicalSubjectModel,
48
103
  second_subject: AstrologicalSubjectModel,
49
104
  use_only_major_aspects: bool = True,
105
+ *,
106
+ axis_orb_limit: Optional[float] = None,
50
107
  ):
51
108
  self.use_only_major_aspects = use_only_major_aspects
52
109
  self.first_subject: AstrologicalSubjectModel = first_subject
@@ -54,26 +111,33 @@ class RelationshipScoreFactory:
54
111
 
55
112
  self.score_value = 0
56
113
  self.relationship_score_description: RelationshipScoreDescription = "Minimal"
57
- self.is_destiny_sign = True
114
+ self.is_destiny_sign = False
58
115
  self.relationship_score_aspects: list[RelationshipScoreAspectModel] = []
59
- self._synastry_aspects = SynastryAspects(self.first_subject, self.second_subject).all_aspects
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
60
121
 
61
122
  def _evaluate_destiny_sign(self):
62
123
  """
63
- Evaluates if the subjects share the same sun sign quality and adds points if true.
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).
64
128
  """
65
- if self.first_subject.sun["quality"] == self.second_subject.sun["quality"]:
129
+ if self.first_subject.sun["quality"] == self.second_subject.sun["quality"]: # type: ignore
66
130
  self.is_destiny_sign = True
67
- self.score_value += 5
68
- logging.debug(f"Destiny sign found, adding 5 points, total score: {self.score_value}")
131
+ self.score_value += DESTINY_SIGN_POINTS
132
+ logging.debug(f"Destiny sign found, adding {DESTINY_SIGN_POINTS} points, total score: {self.score_value}")
69
133
 
70
134
  def _evaluate_aspect(self, aspect, points):
71
135
  """
72
- Evaluates an aspect and adds points to the score.
136
+ Processes an aspect and adds points to the total score.
73
137
 
74
138
  Args:
75
- aspect (dict): Aspect information.
76
- points (int): Points to add.
139
+ aspect (dict): Aspect data containing planetary positions and geometry
140
+ points (int): Points to add to the total score
77
141
  """
78
142
  if self.use_only_major_aspects and aspect["aspect"] not in self.MAJOR_ASPECTS:
79
143
  return
@@ -91,93 +155,100 @@ class RelationshipScoreFactory:
91
155
 
92
156
  def _evaluate_sun_sun_main_aspect(self, aspect):
93
157
  """
94
- Evaluates Sun-Sun main aspects and adds points accordingly:
95
- - 8 points for conjunction/opposition/square
96
- - 11 points if the aspect's orbit is <= 2 degrees
158
+ Evaluates Sun-Sun conjunction, opposition, or square aspects.
159
+
160
+ Adds 8 points for standard orbs, 11 points for tight orbs (≤2°).
97
161
 
98
162
  Args:
99
- aspect (dict): Aspect information.
163
+ aspect (dict): Aspect data
100
164
  """
101
165
  if aspect["p1_name"] == "Sun" and aspect["p2_name"] == "Sun" and aspect["aspect"] in {"conjunction", "opposition", "square"}:
102
- points = 11 if aspect["orbit"] <= 2 else 8
166
+ points = MAJOR_ASPECT_POINTS_HIGH_PRECISION if aspect["orbit"] <= HIGH_PRECISION_ORBIT_THRESHOLD else MAJOR_ASPECT_POINTS_STANDARD
103
167
  self._evaluate_aspect(aspect, points)
104
168
 
105
169
  def _evaluate_sun_moon_conjunction(self, aspect):
106
170
  """
107
- Evaluates Sun-Moon conjunctions and adds points accordingly:
108
- - 8 points for conjunction
109
- - 11 points if the aspect's orbit is <= 2 degrees
171
+ Evaluates Sun-Moon conjunction aspects.
172
+
173
+ Adds 8 points for standard orbs, 11 points for tight orbs (≤2°).
110
174
 
111
175
  Args:
112
- aspect (dict): Aspect information.
176
+ aspect (dict): Aspect data
113
177
  """
114
178
  if {aspect["p1_name"], aspect["p2_name"]} == {"Moon", "Sun"} and aspect["aspect"] == "conjunction":
115
- points = 11 if aspect["orbit"] <= 2 else 8
179
+ points = MAJOR_ASPECT_POINTS_HIGH_PRECISION if aspect["orbit"] <= HIGH_PRECISION_ORBIT_THRESHOLD else MAJOR_ASPECT_POINTS_STANDARD
116
180
  self._evaluate_aspect(aspect, points)
117
181
 
118
182
  def _evaluate_sun_sun_other_aspects(self, aspect):
119
183
  """
120
- Evaluates Sun-Sun aspects that are not conjunctions and adds points accordingly:
121
- - 4 points for other aspects
184
+ Evaluates Sun-Sun aspects other than conjunction, opposition, or square.
185
+
186
+ Adds 4 points for any qualifying aspect.
122
187
 
123
188
  Args:
124
- aspect (dict): Aspect information.
189
+ aspect (dict): Aspect data
125
190
  """
126
191
  if aspect["p1_name"] == "Sun" and aspect["p2_name"] == "Sun" and aspect["aspect"] not in {"conjunction", "opposition", "square"}:
127
- points = 4
192
+ points = MINOR_ASPECT_POINTS
128
193
  self._evaluate_aspect(aspect, points)
129
194
 
130
195
  def _evaluate_sun_moon_other_aspects(self, aspect):
131
196
  """
132
- Evaluates Sun-Moon aspects that are not conjunctions and adds points accordingly:
133
- - 4 points for other aspects
197
+ Evaluates Sun-Moon aspects other than conjunctions.
198
+
199
+ Adds 4 points for any qualifying aspect.
134
200
 
135
201
  Args:
136
- aspect (dict): Aspect information.
202
+ aspect (dict): Aspect data
137
203
  """
138
204
  if {aspect["p1_name"], aspect["p2_name"]} == {"Moon", "Sun"} and aspect["aspect"] != "conjunction":
139
- points = 4
205
+ points = MINOR_ASPECT_POINTS
140
206
  self._evaluate_aspect(aspect, points)
141
207
 
142
208
  def _evaluate_sun_ascendant_aspect(self, aspect):
143
209
  """
144
- Evaluates Sun-Ascendant aspects and adds points accordingly:
145
- - 4 points for any aspect
210
+ Evaluates Sun-Ascendant aspects.
211
+
212
+ Adds 4 points for any aspect between Sun and Ascendant.
146
213
 
147
214
  Args:
148
- aspect (dict): Aspect information.
215
+ aspect (dict): Aspect data
149
216
  """
150
217
  if {aspect["p1_name"], aspect["p2_name"]} == {"Sun", "Ascendant"}:
151
- points = 4
218
+ points = SUN_ASCENDANT_ASPECT_POINTS
152
219
  self._evaluate_aspect(aspect, points)
153
220
 
154
221
  def _evaluate_moon_ascendant_aspect(self, aspect):
155
222
  """
156
- Evaluates Moon-Ascendant aspects and adds points accordingly:
157
- - 4 points for any aspect
223
+ Evaluates Moon-Ascendant aspects.
224
+
225
+ Adds 4 points for any aspect between Moon and Ascendant.
158
226
 
159
227
  Args:
160
- aspect (dict): Aspect information.
228
+ aspect (dict): Aspect data
161
229
  """
162
230
  if {aspect["p1_name"], aspect["p2_name"]} == {"Moon", "Ascendant"}:
163
- points = 4
231
+ points = MOON_ASCENDANT_ASPECT_POINTS
164
232
  self._evaluate_aspect(aspect, points)
165
233
 
166
234
  def _evaluate_venus_mars_aspect(self, aspect):
167
235
  """
168
- Evaluates Venus-Mars aspects and adds points accordingly:
169
- - 4 points for any aspect
236
+ Evaluates Venus-Mars aspects.
237
+
238
+ Adds 4 points for any aspect between Venus and Mars.
170
239
 
171
240
  Args:
172
- aspect (dict): Aspect information.
241
+ aspect (dict): Aspect data
173
242
  """
174
243
  if {aspect["p1_name"], aspect["p2_name"]} == {"Venus", "Mars"}:
175
- points = 4
244
+ points = VENUS_MARS_ASPECT_POINTS
176
245
  self._evaluate_aspect(aspect, points)
177
246
 
178
247
  def _evaluate_relationship_score_description(self):
179
248
  """
180
- Evaluates the relationship score description based on the total score.
249
+ Determines the categorical description based on the numerical score.
250
+
251
+ Maps the total score to predefined description ranges.
181
252
  """
182
253
  for description, threshold in self.SCORE_MAPPING:
183
254
  if self.score_value < threshold:
@@ -186,10 +257,11 @@ class RelationshipScoreFactory:
186
257
 
187
258
  def get_relationship_score(self):
188
259
  """
189
- Calculates the relationship score based on synastry aspects.
260
+ Calculates the complete relationship score using all evaluation methods.
190
261
 
191
262
  Returns:
192
- RelationshipScoreModel: The calculated relationship score.
263
+ RelationshipScoreModel: Score object containing numerical value, description,
264
+ destiny sign status, contributing aspects, and subject data.
193
265
  """
194
266
  self._evaluate_destiny_sign()
195
267
 
@@ -218,10 +290,12 @@ if __name__ == "__main__":
218
290
 
219
291
  setup_logging(level="critical")
220
292
 
221
- john = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
222
- yoko = AstrologicalSubjectFactory.from_birth_data("Yoko Ono", 1933, 2, 18, 18, 30, "Tokyo", "JP")
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")
223
295
 
224
296
  factory = RelationshipScoreFactory(john, yoko)
225
297
  score = factory.get_relationship_score()
226
- print(score)
227
298
 
299
+ # Remove subjects key
300
+ score.subjects = []
301
+ print(score.model_dump_json(indent=4))