kerykeion 4.24.7__py3-none-any.whl → 4.25.1__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.

@@ -0,0 +1,200 @@
1
+ from typing import Union
2
+
3
+ from kerykeion import AstrologicalSubject
4
+ from kerykeion import KerykeionException
5
+ from kerykeion.kr_types.kr_models import CompositeSubjectModel, AstrologicalSubjectModel
6
+ from kerykeion.kr_types.kr_literals import ZodiacType, PerspectiveType, HousesSystemIdentifier, SiderealMode, Planet, Houses, AxialCusps, CompositeChartType
7
+ from kerykeion.utilities import (
8
+ get_kerykeion_point_from_degree,
9
+ get_planet_house,
10
+ circular_mean,
11
+ calculate_moon_phase
12
+ )
13
+
14
+
15
+ class CompositeSubjectFactory:
16
+ """
17
+ Factory class to create a Composite Subject Model from two Astrological Subjects
18
+ Currently, the only available method for creating composite charts is the midpoint method.
19
+ The composite houses and planets are calculated based on the midpoint of the corresponding points of the two subjects.
20
+ The house are then reordered to match the original house system of the first subject.
21
+
22
+ Args:
23
+ first_subject (AstrologicalSubject): First astrological subject
24
+ second_subject (AstrologicalSubject): Second astrological subject
25
+ chart_name (str): Name of the composite chart. If None, it will be automatically generated.
26
+ """
27
+
28
+ model: Union[CompositeSubjectModel, None]
29
+ first_subject: AstrologicalSubjectModel
30
+ second_subject: AstrologicalSubjectModel
31
+ name: str
32
+ composite_chart_type: CompositeChartType
33
+ zodiac_type: ZodiacType
34
+ sidereal_mode: Union[SiderealMode, None]
35
+ houses_system_identifier: HousesSystemIdentifier
36
+ houses_system_name: str
37
+ perspective_type: PerspectiveType
38
+ planets_names_list: list[Planet]
39
+ houses_names_list: list[Houses]
40
+ axial_cusps_names_list: list[AxialCusps]
41
+
42
+ def __init__(
43
+ self,
44
+ first_subject: Union[AstrologicalSubject, AstrologicalSubjectModel],
45
+ second_subject: Union[AstrologicalSubject, AstrologicalSubjectModel],
46
+ chart_name: Union[str, None] = None
47
+ ):
48
+ self.model: Union[CompositeSubjectModel, None] = None
49
+ self.composite_chart_type = "Midpoint"
50
+
51
+ # Subjects
52
+ if isinstance(first_subject, AstrologicalSubject) or isinstance(first_subject, AstrologicalSubjectModel):
53
+ self.first_subject = first_subject.model() # type: ignore
54
+ self.second_subject = second_subject.model() # type: ignore
55
+ else:
56
+ self.first_subject = first_subject
57
+ self.second_subject = second_subject
58
+
59
+ # Name
60
+ if chart_name is None:
61
+ self.name = f"{first_subject.name} and {second_subject.name} Composite Chart"
62
+ else:
63
+ self.name = chart_name
64
+
65
+ # Zodiac Type
66
+ if first_subject.zodiac_type != second_subject.zodiac_type:
67
+ raise KerykeionException("Both subjects must have the same zodiac type")
68
+ self.zodiac_type = first_subject.zodiac_type
69
+
70
+ # Sidereal Mode
71
+ if first_subject.sidereal_mode != second_subject.sidereal_mode:
72
+ raise KerykeionException("Both subjects must have the same sidereal mode")
73
+
74
+ if first_subject.sidereal_mode is not None:
75
+ self.sidereal_mode = first_subject.sidereal_mode
76
+ else:
77
+ self.sidereal_mode = None
78
+
79
+ # Houses System
80
+ if first_subject.houses_system_identifier != second_subject.houses_system_identifier:
81
+ raise KerykeionException("Both subjects must have the same houses system")
82
+ self.houses_system_identifier = first_subject.houses_system_identifier
83
+
84
+ # Houses System Name
85
+ if first_subject.houses_system_name != second_subject.houses_system_name:
86
+ raise KerykeionException("Both subjects must have the same houses system name")
87
+ self.houses_system_name = first_subject.houses_system_name
88
+
89
+ # Perspective Type
90
+ if first_subject.perspective_type != second_subject.perspective_type:
91
+ raise KerykeionException("Both subjects must have the same perspective type")
92
+ self.perspective_type = first_subject.perspective_type
93
+
94
+ # Planets Names List
95
+ self.planets_names_list = []
96
+ for planet in first_subject.planets_names_list:
97
+ if planet in second_subject.planets_names_list:
98
+ self.planets_names_list.append(planet)
99
+
100
+ # Houses Names List
101
+ self.houses_names_list = self.first_subject.houses_names_list
102
+
103
+ # Axial Cusps Names List
104
+ self.axial_cusps_names_list = self.first_subject.axial_cusps_names_list
105
+
106
+ def __str__(self):
107
+ return f"Composite Chart Data for {self.name}"
108
+
109
+ def __repr__(self):
110
+ return f"Composite Chart Data for {self.name}"
111
+
112
+ def __eq__(self, other):
113
+ return self.first_subject == other.first_subject and self.second_subject == other.second_subject and self.name == other.chart_name
114
+
115
+ def __ne__(self, other):
116
+ return not self.__eq__(other)
117
+
118
+ def __hash__(self):
119
+ return hash((self.first_subject, self.second_subject, self.name))
120
+
121
+ def __copy__(self):
122
+ return CompositeSubjectFactory(self.first_subject, self.second_subject, self.name)
123
+
124
+ def __setitem__(self, key, value):
125
+ setattr(self, key, value)
126
+
127
+ def __getitem__(self, key):
128
+ return getattr(self, key)
129
+
130
+ def _calculate_midpoint_composite_points_and_houses(self):
131
+ # Houses
132
+ house_degree_list_ut = []
133
+ for house in self.first_subject.houses_names_list:
134
+ house_lower = house.lower()
135
+ self[house_lower] = get_kerykeion_point_from_degree(
136
+ circular_mean(
137
+ self.first_subject[house_lower]["abs_pos"],
138
+ self.second_subject[house_lower]["abs_pos"]
139
+ ),
140
+ house,
141
+ "House"
142
+ )
143
+ house_degree_list_ut.append(self[house_lower]["abs_pos"])
144
+
145
+ house_degree_list_ut = sorted(house_degree_list_ut)
146
+
147
+ # Planets
148
+ common_planets = []
149
+ for planet in self.first_subject.planets_names_list:
150
+ if planet in self.second_subject.planets_names_list:
151
+ common_planets.append(planet)
152
+
153
+ planets = {}
154
+ for planet in common_planets:
155
+ planet_lower = planet.lower()
156
+ planets[planet_lower] = {}
157
+ planets[planet_lower]["abs_pos"] = circular_mean(
158
+ self.first_subject[planet_lower]["abs_pos"],
159
+ self.second_subject[planet_lower]["abs_pos"]
160
+ )
161
+ self[planet_lower] = get_kerykeion_point_from_degree(planets[planet_lower]["abs_pos"], planet, "Planet")
162
+ self[planet_lower]["house"] = get_planet_house(self[planet_lower]['abs_pos'], house_degree_list_ut)
163
+
164
+
165
+ # Axial Cusps
166
+ for cusp in self.first_subject.axial_cusps_names_list:
167
+ cusp_lower = cusp.lower()
168
+ self[cusp_lower] = get_kerykeion_point_from_degree(
169
+ circular_mean(
170
+ self.first_subject[cusp_lower]["abs_pos"],
171
+ self.second_subject[cusp_lower]["abs_pos"]
172
+ ),
173
+ cusp,
174
+ "AxialCusps"
175
+ )
176
+ self[cusp_lower]["house"] = get_planet_house(self[cusp_lower]['abs_pos'], house_degree_list_ut)
177
+
178
+ def _calculate_composite_lunar_phase(self):
179
+ self.lunar_phase = calculate_moon_phase(
180
+ self['moon'].abs_pos,
181
+ self['sun'].abs_pos
182
+ )
183
+
184
+ def get_midpoint_composite_subject_model(self):
185
+ self._calculate_midpoint_composite_points_and_houses()
186
+ self._calculate_composite_lunar_phase()
187
+
188
+ return CompositeSubjectModel(
189
+ **self.__dict__
190
+ )
191
+
192
+
193
+ if __name__ == "__main__":
194
+ from kerykeion.astrological_subject import AstrologicalSubject
195
+
196
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
197
+ second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
198
+
199
+ composite_chart = CompositeSubjectFactory(first, second)
200
+ print(composite_chart.get_midpoint_composite_subject_model().model_dump_json(indent=4))
@@ -13,18 +13,17 @@ class ChartTemplateDictionary(TypedDict):
13
13
  chart_width: float
14
14
  viewbox: str
15
15
  stringTitle: str
16
- stringName: str
17
- bottomLeft0: str
18
- bottomLeft1: str
19
- bottomLeft2: str
20
- bottomLeft3: str
21
- bottomLeft4: str
22
- moon_phase: str
23
- stringLocation: str
24
- stringDateTime: str
25
- stringLat: str
26
- stringLon: str
27
- stringPosition: str
16
+ top_left_0: str
17
+ bottom_left_0: str
18
+ bottom_left_1: str
19
+ bottom_left_2: str
20
+ bottom_left_3: str
21
+ bottom_left_4: str
22
+ top_left_1: str
23
+ top_left_2: str
24
+ top_left_3: str
25
+ top_left_4: str
26
+ top_left_5: str
28
27
 
29
28
  # Font color
30
29
  paper_color_0: str
@@ -81,8 +80,16 @@ class ChartTemplateDictionary(TypedDict):
81
80
  makeZodiac: str
82
81
  makeHouses: str
83
82
  makePlanets: str
84
- elements_percentages: str
85
83
  makePlanetGrid: str
86
84
  makeHousesGrid: str
87
85
 
88
86
  color_style_tag: str
87
+
88
+ fire_string: str
89
+ earth_string: str
90
+ air_string: str
91
+ water_string: str
92
+
93
+ lunar_phase_rotate: str
94
+ lunar_phase_circle_center_x: str
95
+ lunar_phase_circle_radius: str
@@ -40,7 +40,7 @@ Quality = Literal["Cardinal", "Fixed", "Mutable"]
40
40
  """Literal type for Qualities"""
41
41
 
42
42
 
43
- ChartType = Literal["Natal", "ExternalNatal", "Synastry", "Transit"]
43
+ ChartType = Literal["Natal", "ExternalNatal", "Synastry", "Transit", "Composite"]
44
44
  """Literal type for Chart Types"""
45
45
 
46
46
 
@@ -114,9 +114,14 @@ KerykeionChartTheme = Literal["light", "dark", "dark-high-contrast", "classic"]
114
114
  KerykeionChartLanguage = Literal["EN", "FR", "PT", "IT", "CN", "ES", "RU", "TR", "DE", "HI"]
115
115
  """Literal type for Kerykeion Chart Languages"""
116
116
 
117
+
117
118
  RelationshipScoreDescription = Literal["Minimal", "Medium", "Important", "Very Important", "Exceptional", "Rare Exceptional"]
118
119
  """Literal type for Relationship Score Description"""
119
120
 
121
+
122
+ CompositeChartType = Literal["Midpoint"]
123
+ """Literal type for Composite Chart Types"""
124
+
120
125
  AspectName = Literal[
121
126
  "conjunction",
122
127
  "semi-sextile",
@@ -25,7 +25,8 @@ from kerykeion.kr_types import (
25
25
  HousesSystemIdentifier,
26
26
  Houses,
27
27
  SignsEmoji,
28
- RelationshipScoreDescription
28
+ RelationshipScoreDescription,
29
+ PerspectiveType
29
30
  )
30
31
 
31
32
 
@@ -74,6 +75,10 @@ class KerykeionPointModel(SubscriptableBaseModel):
74
75
 
75
76
 
76
77
  class AstrologicalSubjectModel(SubscriptableBaseModel):
78
+ """
79
+ Pydantic Model for Astrological Subject
80
+ """
81
+
77
82
  # Data
78
83
  name: str
79
84
  year: int
@@ -90,7 +95,7 @@ class AstrologicalSubjectModel(SubscriptableBaseModel):
90
95
  sidereal_mode: Union[SiderealMode, None]
91
96
  houses_system_identifier: HousesSystemIdentifier
92
97
  houses_system_name: str
93
- perspective_type: str
98
+ perspective_type: PerspectiveType
94
99
  iso_formatted_local_datetime: str
95
100
  iso_formatted_utc_datetime: str
96
101
  julian_day: float
@@ -198,6 +203,78 @@ class RelationshipScoreModel(SubscriptableBaseModel):
198
203
  subjects: list[AstrologicalSubjectModel]
199
204
 
200
205
 
206
+ class CompositeSubjectModel(SubscriptableBaseModel):
207
+ """
208
+ Pydantic Model for Composite Subject
209
+ """
210
+
211
+ # Data
212
+ name: str
213
+ first_subject: AstrologicalSubjectModel
214
+ second_subject: AstrologicalSubjectModel
215
+ composite_chart_type: str
216
+
217
+ zodiac_type: ZodiacType
218
+ sidereal_mode: Union[SiderealMode, None]
219
+ houses_system_identifier: HousesSystemIdentifier
220
+ houses_system_name: str
221
+ perspective_type: PerspectiveType
222
+
223
+ # Planets
224
+ sun: KerykeionPointModel
225
+ moon: KerykeionPointModel
226
+ mercury: KerykeionPointModel
227
+ venus: KerykeionPointModel
228
+ mars: KerykeionPointModel
229
+ jupiter: KerykeionPointModel
230
+ saturn: KerykeionPointModel
231
+ uranus: KerykeionPointModel
232
+ neptune: KerykeionPointModel
233
+ pluto: KerykeionPointModel
234
+
235
+ # Axes
236
+ ascendant: KerykeionPointModel
237
+ descendant: KerykeionPointModel
238
+ medium_coeli: KerykeionPointModel
239
+ imum_coeli: KerykeionPointModel
240
+
241
+ # Optional Planets:
242
+ chiron: Union[KerykeionPointModel, None]
243
+ mean_lilith: Union[KerykeionPointModel, None]
244
+
245
+ # Houses
246
+ first_house: KerykeionPointModel
247
+ second_house: KerykeionPointModel
248
+ third_house: KerykeionPointModel
249
+ fourth_house: KerykeionPointModel
250
+ fifth_house: KerykeionPointModel
251
+ sixth_house: KerykeionPointModel
252
+ seventh_house: KerykeionPointModel
253
+ eighth_house: KerykeionPointModel
254
+ ninth_house: KerykeionPointModel
255
+ tenth_house: KerykeionPointModel
256
+ eleventh_house: KerykeionPointModel
257
+ twelfth_house: KerykeionPointModel
258
+
259
+ # Nodes
260
+ mean_node: KerykeionPointModel
261
+ true_node: KerykeionPointModel
262
+ mean_south_node: KerykeionPointModel
263
+ true_south_node: KerykeionPointModel
264
+
265
+ planets_names_list: list[Planet]
266
+ """Ordered list of available planets names"""
267
+
268
+ axial_cusps_names_list: list[AxialCusps]
269
+ """Ordered list of available axes names"""
270
+
271
+ houses_names_list: list[Houses]
272
+ """Ordered list of houses names"""
273
+
274
+ lunar_phase: LunarPhaseModel
275
+ """Lunar phase model"""
276
+
277
+
201
278
  class ActiveAspect(TypedDict):
202
279
  name: AspectName
203
280
  orb: int
@@ -116,27 +116,78 @@ class KerykeionLanguageModel(SubscriptableBaseModel):
116
116
  it's used to translate the celestial points and the other labels
117
117
  """
118
118
 
119
- info: str = Field(title="Info", description="The name of the Info label in the chart, in the language")
120
- cusp: str = Field(title="Cusp", description="The name of the Cusp label in the chart, in the language")
121
- longitude: str = Field(title="Longitude", description="The name of the Longitude label in the chart, in the language")
122
- latitude: str = Field(title="Latitude", description="The name of the Latitude label in the chart, in the language")
123
- north: str = Field(title="North", description="The name of the North label in the chart, in the language")
124
- east: str = Field(title="East", description="The name of the East label in the chart, in the language")
125
- south: str = Field(title="South", description="The name of the South label in the chart, in the language")
126
- west: str = Field(title="West", description="The name of the West label in the chart, in the language")
127
- fire: str = Field(title="Fire", description="The name of the Fire label in the chart, in the language")
128
- earth: str = Field(title="Earth", description="The name of the Earth label in the chart, in the language")
129
- air: str = Field(title="Air", description="The name of the Air label in the chart, in the language")
130
- water: str = Field(title="Water", description="The name of the Water label in the chart, in the language")
131
- and_word: str = Field(title="And", description="The name of the And word in the chart, in the language")
132
- transits: str = Field(title="Transits", description="The name of the Transits label in the chart, in the language")
133
- type: str = Field(title="Type", description="The name of the Type label in the chart, in the language")
134
- aspects: str = Field(title="Aspects", description="The name of the Aspects label in the chart, in the language")
135
- planets_and_house: str = Field(title="Planets and Houses", description="The name of the Planets and Houses label in the chart, in the language")
136
- transit_name: str = Field(title="Transit Name", description="The name of the Transit Name label in the chart, in the language")
137
- lunar_phase: str = Field(title="Lunar Phase", description="The name of the Lunar Phase label in the chart, in the language")
138
- day: str = Field(title="Day", description="The name of the Day label in the chart, in the language")
119
+ info: str
120
+ cusp: str
121
+ longitude: str
122
+ latitude: str
123
+ north: str
124
+ east: str
125
+ south: str
126
+ west: str
127
+ fire: str
128
+ earth: str
129
+ air: str
130
+ water: str
131
+ and_word: str
132
+ transits: str
133
+ type: str
134
+ aspects: str
135
+ planets_and_house: str
136
+ transit_name: str
137
+ lunar_phase: str
138
+ day: str
139
139
  celestial_points: KerykeionLanguageCelestialPointModel
140
+ composite_chart: str
141
+ midpoints: str
142
+ north_letter: str
143
+ east_letter: str
144
+ south_letter: str
145
+ west_letter: str
146
+ tropical: str
147
+ sidereal: str
148
+ zodiac: str
149
+ ayanamsa: str
150
+ apparent_geocentric: str
151
+ heliocentric: str
152
+ topocentric: str
153
+ true_geocentric: str
154
+ new_moon: str
155
+ waxing_crescent: str
156
+ first_quarter: str
157
+ waxing_gibbous: str
158
+ full_moon: str
159
+ waning_gibbous: str
160
+ last_quarter: str
161
+ waning_crescent: str
162
+ houses: str
163
+ houses_system_A: str
164
+ houses_system_B: str
165
+ houses_system_C: str
166
+ houses_system_D: str
167
+ houses_system_F: str
168
+ houses_system_H: str
169
+ houses_system_I: str
170
+ houses_system_i: str
171
+ houses_system_K: str
172
+ houses_system_L: str
173
+ houses_system_M: str
174
+ houses_system_N: str
175
+ houses_system_O: str
176
+ houses_system_P: str
177
+ houses_system_Q: str
178
+ houses_system_R: str
179
+ houses_system_S: str
180
+ houses_system_T: str
181
+ houses_system_U: str
182
+ houses_system_V: str
183
+ houses_system_W: str
184
+ houses_system_X: str
185
+ houses_system_Y: str
186
+ Natal: str
187
+ ExternalNatal: str
188
+ Synastry: str
189
+ Transit: str
190
+ Composite: str
140
191
 
141
192
 
142
193
  class KerykeionGeneralSettingsModel(SubscriptableBaseModel):
@@ -221,57 +221,10 @@ if __name__ == "__main__":
221
221
 
222
222
  setup_logging(level="critical")
223
223
 
224
- john = AstrologicalSubject("John", 1940, 10, 9, 18, 30, "Liverpool", "UK")
225
- yoko = AstrologicalSubject("Yoko", 1933, 2, 18, 20, 30, "Tokyo", "JP")
226
-
227
- relationship_score_factory = RelationshipScoreFactory(john, yoko)
228
- relationship_score = relationship_score_factory.get_relationship_score()
229
-
230
- print("John and Yoko relationship score:")
231
- print(relationship_score.score_value)
232
- print(relationship_score.score_description)
233
- print(relationship_score.is_destiny_sign)
234
- print(len(relationship_score.aspects))
235
- print(len(relationship_score_factory._synastry_aspects))
236
-
237
- print("------------------->")
238
- freud = AstrologicalSubject("Freud", 1856, 5, 6, 18, 30, "Freiberg", "DE")
239
- jung = AstrologicalSubject("Jung", 1875, 7, 26, 18, 30, "Kesswil", "CH")
240
-
241
- relationship_score_factory = RelationshipScoreFactory(freud, jung)
242
- relationship_score = relationship_score_factory.get_relationship_score()
243
-
244
- print("Freud and Jung relationship score:")
245
- print(relationship_score.score_value)
246
- print(relationship_score.score_description)
247
- print(relationship_score.is_destiny_sign)
248
- print(len(relationship_score.aspects))
249
- print(len(relationship_score_factory._synastry_aspects))
250
-
251
- print("------------------->")
252
- richart_burton = AstrologicalSubject("Richard Burton", 1925, 11, 10, 15, 00, "Pontrhydyfen", "UK")
253
- liz_taylor = AstrologicalSubject("Elizabeth Taylor", 1932, 2, 27, 2, 30, "London", "UK")
254
-
255
- relationship_score_factory = RelationshipScoreFactory(richart_burton, liz_taylor)
256
- relationship_score = relationship_score_factory.get_relationship_score()
257
-
258
- print("Richard Burton and Elizabeth Taylor relationship score:")
259
- print(relationship_score.score_value)
260
- print(relationship_score.score_description)
261
- print(relationship_score.is_destiny_sign)
262
- print(len(relationship_score.aspects))
263
- print(len(relationship_score_factory._synastry_aspects))
264
-
265
- print("------------------->")
266
- dario_fo = AstrologicalSubject("Dario Fo", 1926, 3, 24, 12, 25, "Sangiano", "IT")
267
- franca_rame = AstrologicalSubject("Franca Rame", 1929, 7, 18, 12, 25, "Parabiago", "IT")
268
-
269
- relationship_score_factory = RelationshipScoreFactory(dario_fo, franca_rame)
270
- relationship_score = relationship_score_factory.get_relationship_score()
271
-
272
- print("Dario Fo and Franca Rame relationship score:")
273
- print(relationship_score.score_value)
274
- print(relationship_score.score_description)
275
- print(relationship_score.is_destiny_sign)
276
- print(len(relationship_score.aspects))
277
- print(len(relationship_score_factory._synastry_aspects))
224
+ giacomo = AstrologicalSubject("Giacomo", 1993, 6, 10, 12, 15, "Montichiari", "IT")
225
+ yoko = AstrologicalSubject("Susie Cox", 1949, 6, 17, 9, 40, "Tucson", "US")
226
+
227
+ factory = RelationshipScoreFactory(giacomo, yoko)
228
+ score = factory.get_relationship_score()
229
+ print(score)
230
+