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.

Files changed (75) hide show
  1. kerykeion/__init__.py +58 -141
  2. kerykeion/aspects/__init__.py +14 -0
  3. kerykeion/aspects/aspects_factory.py +568 -0
  4. kerykeion/aspects/aspects_utils.py +164 -0
  5. kerykeion/astrological_subject_factory.py +1901 -0
  6. kerykeion/backword.py +820 -0
  7. kerykeion/chart_data_factory.py +552 -0
  8. kerykeion/charts/__init__.py +5 -0
  9. kerykeion/charts/chart_drawer.py +2794 -0
  10. kerykeion/charts/charts_utils.py +1840 -0
  11. kerykeion/charts/draw_planets.py +658 -0
  12. kerykeion/charts/templates/aspect_grid_only.xml +596 -0
  13. kerykeion/charts/templates/chart.xml +741 -0
  14. kerykeion/charts/templates/wheel_only.xml +653 -0
  15. kerykeion/charts/themes/black-and-white.css +148 -0
  16. kerykeion/charts/themes/classic.css +113 -0
  17. kerykeion/charts/themes/dark-high-contrast.css +159 -0
  18. kerykeion/charts/themes/dark.css +160 -0
  19. kerykeion/charts/themes/light.css +160 -0
  20. kerykeion/charts/themes/strawberry.css +158 -0
  21. kerykeion/composite_subject_factory.py +408 -0
  22. kerykeion/ephemeris_data_factory.py +443 -0
  23. kerykeion/fetch_geonames.py +105 -61
  24. kerykeion/house_comparison/__init__.py +6 -0
  25. kerykeion/house_comparison/house_comparison_factory.py +103 -0
  26. kerykeion/house_comparison/house_comparison_utils.py +126 -0
  27. kerykeion/kr_types/__init__.py +70 -0
  28. kerykeion/kr_types/chart_template_model.py +20 -0
  29. kerykeion/kr_types/kerykeion_exception.py +20 -0
  30. kerykeion/kr_types/kr_literals.py +20 -0
  31. kerykeion/kr_types/kr_models.py +20 -0
  32. kerykeion/kr_types/settings_models.py +20 -0
  33. kerykeion/planetary_return_factory.py +805 -0
  34. kerykeion/relationship_score_factory.py +301 -0
  35. kerykeion/report.py +779 -0
  36. kerykeion/schemas/__init__.py +106 -0
  37. kerykeion/schemas/chart_template_model.py +367 -0
  38. kerykeion/schemas/kerykeion_exception.py +20 -0
  39. kerykeion/schemas/kr_literals.py +181 -0
  40. kerykeion/schemas/kr_models.py +603 -0
  41. kerykeion/schemas/settings_models.py +188 -0
  42. kerykeion/settings/__init__.py +20 -0
  43. kerykeion/settings/chart_defaults.py +444 -0
  44. kerykeion/settings/config_constants.py +152 -0
  45. kerykeion/settings/kerykeion_settings.py +51 -0
  46. kerykeion/settings/translation_strings.py +1499 -0
  47. kerykeion/settings/translations.py +74 -0
  48. kerykeion/sweph/README.md +3 -0
  49. kerykeion/sweph/ast136/s136108s.se1 +0 -0
  50. kerykeion/sweph/ast136/s136199s.se1 +0 -0
  51. kerykeion/sweph/ast136/s136472s.se1 +0 -0
  52. kerykeion/sweph/ast28/se28978s.se1 +0 -0
  53. kerykeion/sweph/ast50/se50000s.se1 +0 -0
  54. kerykeion/sweph/ast90/se90377s.se1 +0 -0
  55. kerykeion/sweph/ast90/se90482s.se1 +0 -0
  56. kerykeion/sweph/seas_18.se1 +0 -0
  57. kerykeion/sweph/sefstars.txt +1602 -0
  58. kerykeion/transits_time_range_factory.py +302 -0
  59. kerykeion/utilities.py +762 -130
  60. kerykeion-5.1.9.dist-info/METADATA +1793 -0
  61. kerykeion-5.1.9.dist-info/RECORD +63 -0
  62. {kerykeion-3.1.1.dist-info → kerykeion-5.1.9.dist-info}/WHEEL +1 -2
  63. kerykeion-5.1.9.dist-info/licenses/LICENSE +661 -0
  64. kerykeion/aspects.py +0 -331
  65. kerykeion/charts/charts_svg.py +0 -1607
  66. kerykeion/charts/templates/basic.xml +0 -285
  67. kerykeion/charts/templates/extended.xml +0 -294
  68. kerykeion/kr.config.json +0 -464
  69. kerykeion/main.py +0 -595
  70. kerykeion/print_all_data.py +0 -44
  71. kerykeion/relationship_score.py +0 -219
  72. kerykeion/types.py +0 -190
  73. kerykeion-3.1.1.dist-info/METADATA +0 -204
  74. kerykeion-3.1.1.dist-info/RECORD +0 -17
  75. kerykeion-3.1.1.dist-info/top_level.txt +0 -1
@@ -0,0 +1,603 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ This is part of Kerykeion (C) 2025 Giacomo Battaglia
4
+ """
5
+
6
+ from typing import Union, Optional, List, Literal
7
+ from typing_extensions import TypedDict
8
+ from pydantic import BaseModel, Field
9
+ from kerykeion.schemas.kr_literals import AspectName
10
+
11
+ from kerykeion.schemas import (
12
+ LunarPhaseEmoji,
13
+ LunarPhaseName,
14
+ AstrologicalPoint,
15
+ Houses,
16
+ Quality,
17
+ Element,
18
+ Sign,
19
+ ZodiacType,
20
+ SignNumbers,
21
+ PointType,
22
+ SiderealMode,
23
+ HousesSystemIdentifier,
24
+ SignsEmoji,
25
+ RelationshipScoreDescription,
26
+ PerspectiveType,
27
+ AspectMovementType
28
+ )
29
+ from kerykeion.schemas.kr_literals import ReturnType
30
+
31
+
32
+ class SubscriptableBaseModel(BaseModel):
33
+ """
34
+ Pydantic BaseModel with subscriptable support, so you can access the fields as if they were a dictionary.
35
+ """
36
+
37
+ def __getitem__(self, key):
38
+ """Get an attribute using dictionary-style access."""
39
+ return getattr(self, key)
40
+
41
+ def __setitem__(self, key, value):
42
+ """Set an attribute using dictionary-style access."""
43
+ setattr(self, key, value)
44
+
45
+ def __delitem__(self, key):
46
+ """Delete an attribute using dictionary-style access."""
47
+ delattr(self, key)
48
+
49
+ def get(self, key, default = None):
50
+ """Get an attribute with a default value if not found."""
51
+ return getattr(self, key, default)
52
+
53
+
54
+ class LunarPhaseModel(SubscriptableBaseModel):
55
+ """
56
+ Model representing lunar phase information.
57
+
58
+ Attributes:
59
+ degrees_between_s_m: Angular separation between Sun and Moon in degrees.
60
+ moon_phase: Numerical phase identifier for the Moon.
61
+ moon_emoji: Emoji representation of the lunar phase.
62
+ moon_phase_name: Text name of the lunar phase.
63
+ """
64
+ degrees_between_s_m: Union[float, int]
65
+ moon_phase: int
66
+ moon_emoji: LunarPhaseEmoji
67
+ moon_phase_name: LunarPhaseName
68
+
69
+
70
+ class KerykeionPointModel(SubscriptableBaseModel):
71
+ """
72
+ Model representing an astrological celestial point or house cusp.
73
+
74
+ This model contains comprehensive information about celestial objects
75
+ (planets, points) or house cusps including their zodiacal position,
76
+ sign placement, and metadata.
77
+
78
+ Attributes:
79
+ name: The name of the celestial point or house.
80
+ quality: Astrological quality (Cardinal, Fixed, Mutable).
81
+ element: Astrological element (Fire, Earth, Air, Water).
82
+ sign: The zodiac sign the point is located in.
83
+ sign_num: Numerical identifier for the zodiac sign (0-11).
84
+ position: Position within the sign (0-30 degrees).
85
+ abs_pos: Absolute position in the zodiac (0-360 degrees).
86
+ emoji: Unicode emoji representing the point or sign.
87
+ point_type: Type of the celestial point (Planet, House, etc.).
88
+ house: House placement of the point (optional).
89
+ retrograde: Whether the point is in retrograde motion (optional).
90
+ """
91
+
92
+ name: Union[AstrologicalPoint, Houses]
93
+ quality: Quality
94
+ element: Element
95
+ sign: Sign
96
+ sign_num: SignNumbers
97
+ position: float
98
+ abs_pos: float
99
+ emoji: str
100
+ point_type: PointType
101
+ house: Optional[Houses] = None
102
+ retrograde: Optional[bool] = None
103
+ speed: Optional[float] = None
104
+ declination: Optional[float] = None
105
+
106
+
107
+ class AstrologicalBaseModel(SubscriptableBaseModel):
108
+ """
109
+ Base model containing common fields for all astrological subjects.
110
+
111
+ This model serves as the foundation for all astrological chart types,
112
+ providing standard location, time, and configuration data. It supports
113
+ both complete charts (with full location/time data) and composite charts
114
+ (where some fields may be optional).
115
+
116
+ Attributes:
117
+ name: Subject identifier or name.
118
+ city: Location city (optional for composite charts).
119
+ nation: Country code (optional for composite charts).
120
+ lng: Longitude coordinate (optional for composite charts).
121
+ lat: Latitude coordinate (optional for composite charts).
122
+ tz_str: Timezone string (optional for composite charts).
123
+ iso_formatted_local_datetime: Local datetime in ISO format (optional).
124
+ iso_formatted_utc_datetime: UTC datetime in ISO format (optional).
125
+ julian_day: Julian day number for astronomical calculations (optional).
126
+ day_of_week: Day of the week (optional).
127
+ zodiac_type: Type of zodiac system used (Tropical or Sidereal).
128
+ sidereal_mode: Sidereal calculation mode (if applicable).
129
+ houses_system_identifier: House system used for calculations.
130
+ perspective_type: Astrological perspective (geocentric, heliocentric, etc.).
131
+ active_points: List of celestial points included in calculations.
132
+ """
133
+ # Common identification data
134
+ name: str
135
+
136
+ # Common location data (optional for composite charts)
137
+ city: Optional[str] = None
138
+ nation: Optional[str] = None
139
+ lng: Optional[float] = None
140
+ lat: Optional[float] = None
141
+ tz_str: Optional[str] = None
142
+
143
+ # Common time data (optional for composite charts)
144
+ iso_formatted_local_datetime: Optional[str] = None
145
+ iso_formatted_utc_datetime: Optional[str] = None
146
+ julian_day: Optional[float] = None
147
+ day_of_week: Optional[str] = None
148
+
149
+ # Common configuration
150
+ zodiac_type: ZodiacType
151
+ sidereal_mode: Union[SiderealMode, None]
152
+ houses_system_identifier: HousesSystemIdentifier
153
+ houses_system_name: str
154
+ perspective_type: PerspectiveType
155
+
156
+ # Common celestial points
157
+ # Main planets (all optional to support selective calculations)
158
+ sun: Optional[KerykeionPointModel] = None
159
+ moon: Optional[KerykeionPointModel] = None
160
+ mercury: Optional[KerykeionPointModel] = None
161
+ venus: Optional[KerykeionPointModel] = None
162
+ mars: Optional[KerykeionPointModel] = None
163
+ jupiter: Optional[KerykeionPointModel] = None
164
+ saturn: Optional[KerykeionPointModel] = None
165
+ uranus: Optional[KerykeionPointModel] = None
166
+ neptune: Optional[KerykeionPointModel] = None
167
+ pluto: Optional[KerykeionPointModel] = None
168
+
169
+ # Common axes
170
+ ascendant: Optional[KerykeionPointModel] = None
171
+ descendant: Optional[KerykeionPointModel] = None
172
+ medium_coeli: Optional[KerykeionPointModel] = None
173
+ imum_coeli: Optional[KerykeionPointModel] = None
174
+
175
+ # Common optional planets
176
+ chiron: Optional[KerykeionPointModel] = None
177
+ earth: Optional[KerykeionPointModel] = None
178
+ pholus: Optional[KerykeionPointModel] = None
179
+
180
+ # Lilith Points
181
+ mean_lilith: Optional[KerykeionPointModel] = None
182
+ true_lilith: Optional[KerykeionPointModel] = None
183
+
184
+ # Asteroids
185
+ ceres: Optional[KerykeionPointModel] = None
186
+ pallas: Optional[KerykeionPointModel] = None
187
+ juno: Optional[KerykeionPointModel] = None
188
+ vesta: Optional[KerykeionPointModel] = None
189
+
190
+ # Trans-Neptunian Objects
191
+ eris: Optional[KerykeionPointModel] = None
192
+ sedna: Optional[KerykeionPointModel] = None
193
+ haumea: Optional[KerykeionPointModel] = None
194
+ makemake: Optional[KerykeionPointModel] = None
195
+ ixion: Optional[KerykeionPointModel] = None
196
+ orcus: Optional[KerykeionPointModel] = None
197
+ quaoar: Optional[KerykeionPointModel] = None
198
+
199
+ # Fixed Stars
200
+ regulus: Optional[KerykeionPointModel] = None
201
+ spica: Optional[KerykeionPointModel] = None
202
+
203
+ # Arabic Parts
204
+ pars_fortunae: Optional[KerykeionPointModel] = None
205
+ pars_spiritus: Optional[KerykeionPointModel] = None
206
+ pars_amoris: Optional[KerykeionPointModel] = None
207
+ pars_fidei: Optional[KerykeionPointModel] = None
208
+
209
+ # Special Points
210
+ vertex: Optional[KerykeionPointModel] = None
211
+ anti_vertex: Optional[KerykeionPointModel] = None
212
+
213
+ # Common houses
214
+ first_house: KerykeionPointModel
215
+ second_house: KerykeionPointModel
216
+ third_house: KerykeionPointModel
217
+ fourth_house: KerykeionPointModel
218
+ fifth_house: KerykeionPointModel
219
+ sixth_house: KerykeionPointModel
220
+ seventh_house: KerykeionPointModel
221
+ eighth_house: KerykeionPointModel
222
+ ninth_house: KerykeionPointModel
223
+ tenth_house: KerykeionPointModel
224
+ eleventh_house: KerykeionPointModel
225
+ twelfth_house: KerykeionPointModel
226
+
227
+ # Lunar Nodes
228
+ mean_north_lunar_node: Optional[KerykeionPointModel] = None
229
+ true_north_lunar_node: Optional[KerykeionPointModel] = None
230
+ mean_south_lunar_node: Optional[KerykeionPointModel] = None
231
+ true_south_lunar_node: Optional[KerykeionPointModel] = None
232
+
233
+ # Common lists and settings
234
+ houses_names_list: List[Houses] = Field(description="Ordered list of houses names")
235
+ active_points: List[AstrologicalPoint] = Field(description="List of active points in the chart or aspects calculations.")
236
+
237
+ # Common lunar phase data (optional)
238
+ lunar_phase: Optional[LunarPhaseModel] = Field(default=None, description="Lunar phase model")
239
+
240
+
241
+ class AstrologicalSubjectModel(AstrologicalBaseModel):
242
+ """
243
+ Pydantic Model for Astrological Subject
244
+ """
245
+ # Override base model to make location and time data required for subjects
246
+ city: str
247
+ nation: str
248
+ lng: float
249
+ lat: float
250
+ tz_str: str
251
+ iso_formatted_local_datetime: str
252
+ iso_formatted_utc_datetime: str
253
+ julian_day: float
254
+ day_of_week: str
255
+
256
+ # Specific birth/event data
257
+ year: int
258
+ month: int
259
+ day: int
260
+ hour: int
261
+ minute: int
262
+
263
+
264
+ class CompositeSubjectModel(AstrologicalBaseModel):
265
+ """
266
+ Pydantic Model for Composite Subject
267
+ """
268
+ # Specific composite data
269
+ first_subject: AstrologicalSubjectModel
270
+ second_subject: AstrologicalSubjectModel
271
+ composite_chart_type: str
272
+
273
+
274
+ class PlanetReturnModel(AstrologicalBaseModel):
275
+ """
276
+ Pydantic Model for Planet Return
277
+ """
278
+ # Specific return data
279
+ return_type: ReturnType = Field(description="Type of return: Solar or Lunar")
280
+
281
+
282
+ class EphemerisDictModel(SubscriptableBaseModel):
283
+ date: str
284
+ planets: List[KerykeionPointModel]
285
+ houses: List[KerykeionPointModel]
286
+
287
+
288
+ class AspectModel(SubscriptableBaseModel):
289
+ p1_name: str
290
+ p1_owner: str
291
+ p1_abs_pos: float
292
+ p2_name: str
293
+ p2_owner: str
294
+ p2_abs_pos: float
295
+ aspect: str
296
+ orbit: float
297
+ aspect_degrees: int
298
+ diff: float
299
+ p1: int
300
+ p2: int
301
+ aspect_movement: AspectMovementType = Field(
302
+ description="Indicates whether the aspect is applying (planets moving toward exact aspect), "
303
+ "separating (planets moving away from exact aspect), or exact (within tight orb)."
304
+ )
305
+
306
+
307
+ class ZodiacSignModel(SubscriptableBaseModel):
308
+ sign: Sign
309
+ quality: Quality
310
+ element: Element
311
+ emoji: SignsEmoji
312
+ sign_num: SignNumbers
313
+
314
+
315
+ class RelationshipScoreAspectModel(SubscriptableBaseModel):
316
+ p1_name: str
317
+ p2_name: str
318
+ aspect: str
319
+ orbit: float
320
+
321
+
322
+ class RelationshipScoreModel(SubscriptableBaseModel):
323
+ score_value: int
324
+ score_description: RelationshipScoreDescription
325
+ is_destiny_sign: bool
326
+ aspects: List[RelationshipScoreAspectModel]
327
+ subjects: List[AstrologicalSubjectModel]
328
+
329
+
330
+ class ActiveAspect(TypedDict):
331
+ name: AspectName
332
+ orb: int
333
+
334
+
335
+ class TransitMomentModel(SubscriptableBaseModel):
336
+ """
337
+ Model representing a snapshot of astrological transits at a specific moment in time.
338
+
339
+ Captures all active aspects between moving celestial bodies and
340
+ the fixed positions in a person's natal chart at a specific date and time.
341
+ """
342
+ date: str = Field(description="ISO 8601 formatted date and time of the transit moment.")
343
+ aspects: List[AspectModel] = Field(description="List of aspects active at this specific moment.")
344
+
345
+
346
+ class SingleChartAspectsModel(SubscriptableBaseModel):
347
+ """
348
+ Model representing all aspects within a single astrological chart.
349
+
350
+ This model can be used for any type of single chart analysis including:
351
+ - Natal charts
352
+ - Planetary return charts
353
+ - Composite charts
354
+ - Any other single chart type
355
+
356
+ Contains the filtered and relevant aspects for the astrological subject
357
+ based on configured orb settings.
358
+ """
359
+ subject: Union["AstrologicalSubjectModel", "CompositeSubjectModel", "PlanetReturnModel"] = Field(description="The astrological subject for which aspects were calculated.")
360
+ aspects: List[AspectModel] = Field(description="List of calculated aspects within the chart, filtered based on orb settings.")
361
+ active_points: List[AstrologicalPoint] = Field(description="List of active points used in the calculation.")
362
+ active_aspects: List["ActiveAspect"] = Field(description="List of active aspects with their orb settings.")
363
+
364
+
365
+ class DualChartAspectsModel(SubscriptableBaseModel):
366
+ """
367
+ Model representing all aspects between two astrological charts.
368
+
369
+ This model can be used for any type of dual chart analysis including:
370
+ - Synastry (relationship compatibility)
371
+ - Transit comparisons
372
+ - Composite vs natal comparisons
373
+ - Any other dual chart comparison
374
+
375
+ Contains the filtered and relevant aspects between the two charts
376
+ based on configured orb settings.
377
+ """
378
+ first_subject: Union["AstrologicalSubjectModel", "CompositeSubjectModel", "PlanetReturnModel"] = Field(description="The first astrological subject.")
379
+ second_subject: Union["AstrologicalSubjectModel", "CompositeSubjectModel", "PlanetReturnModel"] = Field(description="The second astrological subject.")
380
+ aspects: List[AspectModel] = Field(description="List of calculated aspects between the two charts, filtered based on orb settings.")
381
+ active_points: List[AstrologicalPoint] = Field(description="List of active points used in the calculation.")
382
+ active_aspects: List["ActiveAspect"] = Field(description="List of active aspects with their orb settings.")
383
+
384
+
385
+ # Legacy aliases for backward compatibility
386
+ NatalAspectsModel = SingleChartAspectsModel
387
+ SynastryAspectsModel = DualChartAspectsModel
388
+
389
+
390
+ class TransitsTimeRangeModel(SubscriptableBaseModel):
391
+ """
392
+ Model representing a collection of transit moments for an astrological subject.
393
+
394
+ This model holds a time series of transit snapshots, allowing analysis of
395
+ planetary movements and their aspects to a natal chart over a period of time.
396
+ """
397
+ transits: List[TransitMomentModel] = Field(description="List of transit moments.")
398
+ subject: Optional[AstrologicalSubjectModel] = Field(description="Astrological subject data.")
399
+ dates: Optional[List[str]] = Field(description="ISO 8601 formatted dates of all transit moments.")
400
+
401
+
402
+ class PointInHouseModel(SubscriptableBaseModel):
403
+ """
404
+ Represents an astrological point from one subject positioned within another subject's house.
405
+
406
+ Captures point characteristics and its placement within the target subject's house system
407
+ for house comparison analysis.
408
+
409
+ Attributes:
410
+ point_name: Name of the astrological point
411
+ point_degree: Degree position within its sign
412
+ point_sign: Zodiacal sign containing the point
413
+ point_owner_name: Name of the subject who owns this point
414
+ point_owner_house_number: House number in owner's chart
415
+ point_owner_house_name: House name in owner's chart
416
+ projected_house_number: House number in target subject's chart
417
+ projected_house_name: House name in target subject's chart
418
+ projected_house_owner_name: Name of the target subject
419
+ """
420
+
421
+ point_name: str
422
+ """Name of the astrological point"""
423
+ point_degree: float
424
+ """Degree position of the point within its zodiacal sign"""
425
+ point_sign: str
426
+ """Zodiacal sign containing the point"""
427
+ point_owner_name: str
428
+ """Name of the subject who owns this point"""
429
+ point_owner_house_number: Optional[int]
430
+ """House number in owner's chart"""
431
+ point_owner_house_name: Optional[str]
432
+ """House name in owner's chart"""
433
+ projected_house_number: int
434
+ """House number in target subject's chart"""
435
+ projected_house_name: str
436
+ """House name in target subject's chart"""
437
+ projected_house_owner_name: str
438
+ """Name of the target subject"""
439
+
440
+
441
+ class HouseComparisonModel(SubscriptableBaseModel):
442
+ """
443
+ Bidirectional house comparison analysis between two astrological subjects.
444
+
445
+ Contains results of how astrological points from each subject interact with
446
+ the house system of the other subject.
447
+
448
+ Attributes:
449
+ first_subject_name: Name of the first subject
450
+ second_subject_name: Name of the second subject
451
+ first_points_in_second_houses: First subject's points in second subject's houses
452
+ second_points_in_first_houses: Second subject's points in first subject's houses
453
+ """
454
+
455
+ first_subject_name: str
456
+ """Name of the first subject"""
457
+ second_subject_name: str
458
+ """Name of the second subject"""
459
+ first_points_in_second_houses: List[PointInHouseModel]
460
+ """First subject's points positioned in second subject's houses"""
461
+ second_points_in_first_houses: List[PointInHouseModel]
462
+ """Second subject's points positioned in first subject's houses"""
463
+
464
+
465
+ class ElementDistributionModel(SubscriptableBaseModel):
466
+ """
467
+ Model representing element distribution in a chart.
468
+
469
+ Attributes:
470
+ fire: Fire element points total
471
+ earth: Earth element points total
472
+ air: Air element points total
473
+ water: Water element points total
474
+ fire_percentage: Fire element percentage
475
+ earth_percentage: Earth element percentage
476
+ air_percentage: Air element percentage
477
+ water_percentage: Water element percentage
478
+ """
479
+ fire: float
480
+ earth: float
481
+ air: float
482
+ water: float
483
+ fire_percentage: int
484
+ earth_percentage: int
485
+ air_percentage: int
486
+ water_percentage: int
487
+
488
+
489
+ class QualityDistributionModel(SubscriptableBaseModel):
490
+ """
491
+ Model representing quality distribution in a chart.
492
+
493
+ Attributes:
494
+ cardinal: Cardinal quality points total
495
+ fixed: Fixed quality points total
496
+ mutable: Mutable quality points total
497
+ cardinal_percentage: Cardinal quality percentage
498
+ fixed_percentage: Fixed quality percentage
499
+ mutable_percentage: Mutable quality percentage
500
+ """
501
+ cardinal: float
502
+ fixed: float
503
+ mutable: float
504
+ cardinal_percentage: int
505
+ fixed_percentage: int
506
+ mutable_percentage: int
507
+
508
+
509
+ class SingleChartDataModel(SubscriptableBaseModel):
510
+ """
511
+ Chart data model for single-subject astrological charts.
512
+
513
+ This model contains all pure data from single-subject charts including planetary
514
+ positions, internal aspects, element/quality distributions, and location data.
515
+ Used for chart types that analyze a single astrological subject.
516
+
517
+ Supported chart types:
518
+ - Natal: Birth chart with internal planetary aspects
519
+ - Composite: Midpoint relationship chart with internal aspects
520
+ - SingleReturnChart: Single planetary return with internal aspects
521
+
522
+ Attributes:
523
+ chart_type: Type of single chart (Natal, Composite, SingleReturnChart)
524
+ subject: The astrological subject being analyzed
525
+ aspects: Internal aspects within the chart
526
+ element_distribution: Distribution of elemental energies
527
+ quality_distribution: Distribution of modal qualities
528
+ active_points: Celestial points included in calculations
529
+ active_aspects: Aspect types and orb settings used
530
+ """
531
+
532
+ # Chart identification
533
+ chart_type: Literal["Natal", "Composite", "SingleReturnChart"]
534
+
535
+ # Single chart subject
536
+ subject: Union["AstrologicalSubjectModel", "CompositeSubjectModel", "PlanetReturnModel"]
537
+
538
+ # Internal aspects analysis
539
+ aspects: List[AspectModel]
540
+
541
+ # Element and quality distributions
542
+ element_distribution: "ElementDistributionModel"
543
+ quality_distribution: "QualityDistributionModel"
544
+
545
+ # Configuration and metadata
546
+ active_points: List[AstrologicalPoint]
547
+ active_aspects: List["ActiveAspect"]
548
+
549
+
550
+ class DualChartDataModel(SubscriptableBaseModel):
551
+ """
552
+ Chart data model for dual-subject astrological charts.
553
+
554
+ This model contains all pure data from dual-subject charts including both subjects,
555
+ inter-chart aspects, house comparisons, relationship analysis, and combined
556
+ element/quality distributions. Used for chart types that compare or overlay
557
+ two astrological subjects.
558
+
559
+ Supported chart types:
560
+ - Transit: Natal chart with current planetary transits
561
+ - Synastry: Relationship compatibility between two people
562
+ - Return: Natal chart with planetary return comparison
563
+
564
+ Attributes:
565
+ chart_type: Type of dual chart (Transit, Synastry, Return)
566
+ first_subject: Primary astrological subject (natal, base chart)
567
+ second_subject: Secondary astrological subject (transit, partner, return)
568
+ aspects: Inter-chart aspects between the two subjects
569
+ house_comparison: House overlay analysis between subjects
570
+ relationship_score: Compatibility scoring (synastry only)
571
+ element_distribution: Combined elemental distribution
572
+ quality_distribution: Combined modal distribution
573
+ active_points: Celestial points included in calculations
574
+ active_aspects: Aspect types and orb settings used
575
+ """
576
+
577
+ # Chart identification
578
+ chart_type: Literal["Transit", "Synastry", "DualReturnChart"]
579
+
580
+ # Dual chart subjects
581
+ first_subject: Union["AstrologicalSubjectModel", "CompositeSubjectModel", "PlanetReturnModel"]
582
+ second_subject: Union["AstrologicalSubjectModel", "PlanetReturnModel"]
583
+
584
+ # Inter-chart aspects analysis
585
+ aspects: List[AspectModel]
586
+
587
+ # House comparison analysis
588
+ house_comparison: Optional["HouseComparisonModel"] = None
589
+
590
+ # Relationship analysis (synastry only)
591
+ relationship_score: Optional["RelationshipScoreModel"] = None
592
+
593
+ # Combined element and quality distributions
594
+ element_distribution: "ElementDistributionModel"
595
+ quality_distribution: "QualityDistributionModel"
596
+
597
+ # Configuration and metadata
598
+ active_points: List[AstrologicalPoint]
599
+ active_aspects: List["ActiveAspect"]
600
+
601
+
602
+ # Union type for all chart data models
603
+ ChartDataModel = Union[SingleChartDataModel, DualChartDataModel]