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
@@ -0,0 +1,148 @@
1
+ :root {
2
+ /* -------- */
3
+ /* General */
4
+ /* ------- */
5
+ --kerykeion-color-black: #000000;
6
+ --kerykeion-color-white: #ffffff;
7
+
8
+ --kerykeion-color-neutral-content: #111111;
9
+ --kerykeion-color-base-content: #111111;
10
+ --kerykeion-color-primary: #222222;
11
+ --kerykeion-color-secondary: #444444;
12
+ --kerykeion-color-accent: #666666;
13
+ --kerykeion-color-neutral: #1a1a1a;
14
+ --kerykeion-color-base-100: #ffffff;
15
+ --kerykeion-color-info: #222222;
16
+ --kerykeion-color-info-content: #ffffff;
17
+ --kerykeion-color-success: #333333;
18
+ --kerykeion-color-warning: #555555;
19
+ --kerykeion-color-error: #777777;
20
+
21
+ /* Zodiac */
22
+ --kerykeion-color-base-200: #f0f0f0;
23
+ --kerykeion-color-base-300: #d9d9d9;
24
+
25
+ /* ----------- */
26
+ /* Chart Color */
27
+ /* ----------- */
28
+
29
+ /* Main colors */
30
+ --kerykeion-chart-color-paper-0: var(--kerykeion-color-neutral-content);
31
+ --kerykeion-chart-color-paper-1: var(--kerykeion-color-base-100);
32
+
33
+ /* Zodiac Sign Sectors */
34
+ --kerykeion-chart-color-zodiac-bg-0: var(--kerykeion-color-base-200);
35
+ --kerykeion-chart-color-zodiac-bg-1: var(--kerykeion-color-base-300);
36
+ --kerykeion-chart-color-zodiac-bg-2: var(--kerykeion-color-base-200);
37
+ --kerykeion-chart-color-zodiac-bg-3: var(--kerykeion-color-base-300);
38
+ --kerykeion-chart-color-zodiac-bg-4: var(--kerykeion-color-base-200);
39
+ --kerykeion-chart-color-zodiac-bg-5: var(--kerykeion-color-base-300);
40
+ --kerykeion-chart-color-zodiac-bg-6: var(--kerykeion-color-base-200);
41
+ --kerykeion-chart-color-zodiac-bg-7: var(--kerykeion-color-base-300);
42
+ --kerykeion-chart-color-zodiac-bg-8: var(--kerykeion-color-base-200);
43
+ --kerykeion-chart-color-zodiac-bg-9: var(--kerykeion-color-base-300);
44
+ --kerykeion-chart-color-zodiac-bg-10: var(--kerykeion-color-base-200);
45
+ --kerykeion-chart-color-zodiac-bg-11: var(--kerykeion-color-base-300);
46
+
47
+ /* Zodiac Sign Rings */
48
+ --kerykeion-chart-color-zodiac-radix-ring-0: var(--kerykeion-color-black);
49
+ --kerykeion-chart-color-zodiac-radix-ring-1: var(--kerykeion-color-black);
50
+ --kerykeion-chart-color-zodiac-radix-ring-2: var(--kerykeion-color-black);
51
+ --kerykeion-chart-color-zodiac-transit-ring-0: var(--kerykeion-color-black);
52
+ --kerykeion-chart-color-zodiac-transit-ring-1: var(--kerykeion-color-black);
53
+ --kerykeion-chart-color-zodiac-transit-ring-2: var(--kerykeion-color-black);
54
+ --kerykeion-chart-color-zodiac-transit-ring-3: var(--kerykeion-color-black);
55
+ --kerykeion-chart-color-houses-radix-line: var(--kerykeion-color-base-content);
56
+ --kerykeion-chart-color-houses-transit-line: var(--kerykeion-color-base-content);
57
+
58
+ /* Aspects */
59
+ --kerykeion-chart-color-conjunction: #222222;
60
+ --kerykeion-chart-color-semi-sextile: #333333;
61
+ --kerykeion-chart-color-semi-square: #444444;
62
+ --kerykeion-chart-color-sextile: #333333;
63
+ --kerykeion-chart-color-quintile: #555555;
64
+ --kerykeion-chart-color-square: #000000;
65
+ --kerykeion-chart-color-trine: #222222;
66
+ --kerykeion-chart-color-sesquiquadrate: #444444;
67
+ --kerykeion-chart-color-biquintile: #555555;
68
+ --kerykeion-chart-color-quincunx: #444444;
69
+ --kerykeion-chart-color-opposition: #000000;
70
+
71
+ /* Planets */
72
+ --kerykeion-chart-color-sun: #000000;
73
+ --kerykeion-chart-color-moon: #000000;
74
+ --kerykeion-chart-color-mercury: #000000;
75
+ --kerykeion-chart-color-venus: #000000;
76
+ --kerykeion-chart-color-mars: #000000;
77
+ --kerykeion-chart-color-jupiter: #000000;
78
+ --kerykeion-chart-color-saturn: #000000;
79
+ --kerykeion-chart-color-uranus: #000000;
80
+ --kerykeion-chart-color-neptune: #000000;
81
+ --kerykeion-chart-color-pluto: #000000;
82
+ --kerykeion-chart-color-true-node: #000000;
83
+ --kerykeion-chart-color-mean-node: #000000;
84
+ --kerykeion-chart-color-chiron: #000000;
85
+ --kerykeion-chart-color-first-house: #000000;
86
+ --kerykeion-chart-color-tenth-house: #000000;
87
+ --kerykeion-chart-color-seventh-house: #000000;
88
+ --kerykeion-chart-color-fourth-house: #000000;
89
+ --kerykeion-chart-color-mean-lilith: #000000;
90
+ --kerykeion-chart-color-true-lilith: #000000;
91
+ --kerykeion-chart-color-ceres: #000000;
92
+ --kerykeion-chart-color-pallas: #000000;
93
+ --kerykeion-chart-color-juno: #000000;
94
+ --kerykeion-chart-color-vesta: #000000;
95
+ --kerykeion-chart-color-pars-fortunae: #000000;
96
+ --kerykeion-chart-color-vertex: #000000;
97
+ --kerykeion-chart-color-east-point: #000000;
98
+ --kerykeion-chart-color-eris: #000000;
99
+ --kerykeion-chart-color-earth: #000000;
100
+ --kerykeion-chart-color-pholus: #000000;
101
+ --kerykeion-chart-color-sedna: #000000;
102
+ --kerykeion-chart-color-haumea: #000000;
103
+ --kerykeion-chart-color-makemake: #000000;
104
+ --kerykeion-chart-color-ixion: #000000;
105
+ --kerykeion-chart-color-orcus: #000000;
106
+ --kerykeion-chart-color-quaoar: #000000;
107
+ --kerykeion-chart-color-regulus: #000000;
108
+ --kerykeion-chart-color-spica: #000000;
109
+ --kerykeion-chart-color-anti-vertex: #000000;
110
+
111
+ /* Arab Parts */
112
+ --kerykeion-chart-color-pars-spiritus: #000000;
113
+ --kerykeion-chart-color-pars-amoris: #000000;
114
+ --kerykeion-chart-color-pars-fortunae: #000000;
115
+ --kerykeion-chart-color-pars-fidei: #000000;
116
+
117
+ /* Zodiac Signs */
118
+ --kerykeion-chart-color-zodiac-icon-0: #000000;
119
+ --kerykeion-chart-color-zodiac-icon-1: #000000;
120
+ --kerykeion-chart-color-zodiac-icon-2: #000000;
121
+ --kerykeion-chart-color-zodiac-icon-3: #000000;
122
+ --kerykeion-chart-color-zodiac-icon-4: #000000;
123
+ --kerykeion-chart-color-zodiac-icon-5: #000000;
124
+ --kerykeion-chart-color-zodiac-icon-6: #000000;
125
+ --kerykeion-chart-color-zodiac-icon-7: #000000;
126
+ --kerykeion-chart-color-zodiac-icon-8: #000000;
127
+ --kerykeion-chart-color-zodiac-icon-9: #000000;
128
+ --kerykeion-chart-color-zodiac-icon-10: #000000;
129
+ --kerykeion-chart-color-zodiac-icon-11: #000000;
130
+
131
+ /* Elements Percentage */
132
+ --kerykeion-chart-color-air-percentage: #111111;
133
+ --kerykeion-chart-color-earth-percentage: #333333;
134
+ --kerykeion-chart-color-fire-percentage: #555555;
135
+ --kerykeion-chart-color-water-percentage: #777777;
136
+
137
+ /* Modalities Percentage */
138
+ --kerykeion-chart-color-cardinal-percentage: #222222;
139
+ --kerykeion-chart-color-fixed-percentage: #444444;
140
+ --kerykeion-chart-color-mutable-percentage: #666666;
141
+
142
+ /* Aspects */
143
+ --kerykeion-chart-color-lunar-phase-0: var(--kerykeion-color-black);
144
+ --kerykeion-chart-color-lunar-phase-1: var(--kerykeion-color-white);
145
+
146
+ /* Houses Numbers */
147
+ --kerykeion-chart-color-house-number: #000000;
148
+ }
@@ -79,6 +79,17 @@
79
79
  --kerykeion-chart-color-vertex: #52064e;
80
80
  --kerykeion-chart-color-east-point: #482b7f;
81
81
  --kerykeion-chart-color-eris: #800000;
82
+ --kerykeion-chart-color-earth: #6a2d04;
83
+ --kerykeion-chart-color-pholus: #5a5a5a;
84
+ --kerykeion-chart-color-sedna: #b8860b;
85
+ --kerykeion-chart-color-haumea: #8b4513;
86
+ --kerykeion-chart-color-makemake: #a0522d;
87
+ --kerykeion-chart-color-ixion: #556b2f;
88
+ --kerykeion-chart-color-orcus: #2f4f4f;
89
+ --kerykeion-chart-color-quaoar: #8a2be2;
90
+ --kerykeion-chart-color-regulus: #ffd700;
91
+ --kerykeion-chart-color-spica: #87ceeb;
92
+ --kerykeion-chart-color-anti-vertex: #4b0082;
82
93
 
83
94
  /* Arab Parts */
84
95
  --kerykeion-chart-color-pars-spiritus: #095242;
@@ -107,6 +107,17 @@
107
107
  --kerykeion-chart-color-vertex: var(--kerykeion-color-secondary);
108
108
  --kerykeion-chart-color-east-point: var(--kerykeion-color-primary);
109
109
  --kerykeion-chart-color-eris: var(--kerykeion-color-error);
110
+ --kerykeion-chart-color-earth: var(--kerykeion-color-warning);
111
+ --kerykeion-chart-color-pholus: var(--kerykeion-color-secondary);
112
+ --kerykeion-chart-color-sedna: var(--kerykeion-color-warning);
113
+ --kerykeion-chart-color-haumea: var(--kerykeion-color-accent);
114
+ --kerykeion-chart-color-makemake: var(--kerykeion-color-primary);
115
+ --kerykeion-chart-color-ixion: var(--kerykeion-color-secondary);
116
+ --kerykeion-chart-color-orcus: var(--kerykeion-color-accent);
117
+ --kerykeion-chart-color-quaoar: var(--kerykeion-color-primary);
118
+ --kerykeion-chart-color-regulus: var(--kerykeion-color-warning);
119
+ --kerykeion-chart-color-spica: var(--kerykeion-color-accent);
120
+ --kerykeion-chart-color-anti-vertex: var(--kerykeion-color-secondary);
110
121
 
111
122
  /* Arab Parts */
112
123
  --kerykeion-chart-color-pars-spiritus: var(--kerykeion-color-success);
@@ -108,6 +108,17 @@
108
108
  --kerykeion-chart-color-vertex: var(--kerykeion-color-secondary);
109
109
  --kerykeion-chart-color-east-point: var(--kerykeion-color-primary);
110
110
  --kerykeion-chart-color-eris: var(--kerykeion-color-error);
111
+ --kerykeion-chart-color-earth: var(--kerykeion-color-warning);
112
+ --kerykeion-chart-color-pholus: var(--kerykeion-color-secondary);
113
+ --kerykeion-chart-color-sedna: var(--kerykeion-color-warning);
114
+ --kerykeion-chart-color-haumea: var(--kerykeion-color-accent);
115
+ --kerykeion-chart-color-makemake: var(--kerykeion-color-primary);
116
+ --kerykeion-chart-color-ixion: var(--kerykeion-color-secondary);
117
+ --kerykeion-chart-color-orcus: var(--kerykeion-color-accent);
118
+ --kerykeion-chart-color-quaoar: var(--kerykeion-color-primary);
119
+ --kerykeion-chart-color-regulus: var(--kerykeion-color-warning);
120
+ --kerykeion-chart-color-spica: var(--kerykeion-color-accent);
121
+ --kerykeion-chart-color-anti-vertex: var(--kerykeion-color-secondary);
111
122
 
112
123
  /* Arab Parts */
113
124
  --kerykeion-chart-color-pars-spiritus: var(--kerykeion-color-success);
@@ -108,6 +108,17 @@
108
108
  --kerykeion-chart-color-vertex: var(--kerykeion-color-secondary);
109
109
  --kerykeion-chart-color-east-point: var(--kerykeion-color-primary);
110
110
  --kerykeion-chart-color-eris: var(--kerykeion-color-error);
111
+ --kerykeion-chart-color-earth: var(--kerykeion-color-warning);
112
+ --kerykeion-chart-color-pholus: var(--kerykeion-color-secondary);
113
+ --kerykeion-chart-color-sedna: var(--kerykeion-color-warning);
114
+ --kerykeion-chart-color-haumea: var(--kerykeion-color-accent);
115
+ --kerykeion-chart-color-makemake: var(--kerykeion-color-primary);
116
+ --kerykeion-chart-color-ixion: var(--kerykeion-color-secondary);
117
+ --kerykeion-chart-color-orcus: var(--kerykeion-color-accent);
118
+ --kerykeion-chart-color-quaoar: var(--kerykeion-color-primary);
119
+ --kerykeion-chart-color-regulus: var(--kerykeion-color-warning);
120
+ --kerykeion-chart-color-spica: var(--kerykeion-color-accent);
121
+ --kerykeion-chart-color-anti-vertex: var(--kerykeion-color-secondary);
111
122
 
112
123
  /* Arab Parts */
113
124
  --kerykeion-chart-color-pars-spiritus: var(--kerykeion-color-success);
@@ -107,6 +107,16 @@
107
107
  --kerykeion-chart-color-east-point: var(--kerykeion-color-primary);
108
108
  --kerykeion-chart-color-eris: var(--kerykeion-color-error);
109
109
  --kerykeion-chart-color-earth: var(--kerykeion-color-warning);
110
+ --kerykeion-chart-color-pholus: var(--kerykeion-color-secondary);
111
+ --kerykeion-chart-color-sedna: var(--kerykeion-color-warning);
112
+ --kerykeion-chart-color-haumea: var(--kerykeion-color-accent);
113
+ --kerykeion-chart-color-makemake: var(--kerykeion-color-primary);
114
+ --kerykeion-chart-color-ixion: var(--kerykeion-color-secondary);
115
+ --kerykeion-chart-color-orcus: var(--kerykeion-color-accent);
116
+ --kerykeion-chart-color-quaoar: var(--kerykeion-color-primary);
117
+ --kerykeion-chart-color-regulus: var(--kerykeion-color-warning);
118
+ --kerykeion-chart-color-spica: var(--kerykeion-color-accent);
119
+ --kerykeion-chart-color-anti-vertex: var(--kerykeion-color-secondary);
110
120
 
111
121
  /* Arab Parts */
112
122
  --kerykeion-chart-color-pars-spiritus: var(--kerykeion-color-success);
@@ -1,10 +1,50 @@
1
- from typing import Union, TYPE_CHECKING
1
+ """
2
+ Composite Subject Factory Module
3
+
4
+ This module provides functionality for creating composite astrological charts from two
5
+ individual astrological subjects. A composite chart represents the relationship between
6
+ two people by calculating midpoint positions between corresponding planetary placements
7
+ and house cusps.
8
+
9
+ The module implements the midpoint composite technique, which is the most commonly used
10
+ method for relationship astrology. This technique creates a single chart that symbolizes
11
+ the energy and dynamics of the relationship itself, rather than comparing individual charts.
12
+
13
+ Key Features:
14
+ - Midpoint calculation for all planetary positions
15
+ - Midpoint calculation for house cusp positions
16
+ - Proper handling of zodiacal boundary crossings (0°/360°)
17
+ - Validation of compatible astrological settings between subjects
18
+ - Lunar phase calculation for composite charts
19
+ - Support for all standard astrological points and house systems
20
+
21
+ Classes:
22
+ CompositeSubjectFactory: Main factory class for creating composite charts
23
+
24
+ Dependencies:
25
+ - AstrologicalSubjectFactory: For working with individual astrological subjects
26
+ - Various schemas modules: For type definitions and models
27
+ - utilities module: For astrological calculations and helper functions
28
+
29
+ Example Usage:
30
+ >>> from kerykeion import AstrologicalSubjectFactory, CompositeSubjectFactory
31
+ >>> person1 = AstrologicalSubjectFactory.from_birth_data(...)
32
+ >>> person2 = AstrologicalSubjectFactory.from_birth_data(...)
33
+ >>> composite = CompositeSubjectFactory(person1, person2)
34
+ >>> composite_chart = composite.get_midpoint_composite_subject_model()
35
+
36
+ Author: Giacomo Battaglia
37
+ Copyright: (C) 2025 Kerykeion Project
38
+ License: AGPL-3.0
39
+ """
40
+
41
+ from typing import Union
2
42
 
3
43
  # Fix the circular import by changing this import
4
44
  from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
5
- from kerykeion.kr_types.kerykeion_exception import KerykeionException
6
- from kerykeion.kr_types.kr_models import CompositeSubjectModel, AstrologicalSubjectModel
7
- from kerykeion.kr_types.kr_literals import ZodiacType, PerspectiveType, HousesSystemIdentifier, SiderealMode, AstrologicalPoint, Houses, CompositeChartType
45
+ from kerykeion.schemas.kerykeion_exception import KerykeionException
46
+ from kerykeion.schemas.kr_models import CompositeSubjectModel, AstrologicalSubjectModel
47
+ from kerykeion.schemas.kr_literals import ZodiacType, PerspectiveType, HousesSystemIdentifier, SiderealMode, AstrologicalPoint, Houses, CompositeChartType
8
48
  from kerykeion.utilities import (
9
49
  get_kerykeion_point_from_degree,
10
50
  get_planet_house,
@@ -17,15 +57,48 @@ from kerykeion.utilities import (
17
57
 
18
58
  class CompositeSubjectFactory:
19
59
  """
20
- Factory class to create a Composite Subject Model from two Astrological Subjects
21
- Currently, the only available method for creating composite charts is the midpoint method.
22
- The composite houses and planets are calculated based on the midpoint of the corresponding points of the two subjects.
23
- The house are then reordered to match the original house system of the first subject.
24
-
25
- Args:
26
- first_subject (AstrologicalSubject): First astrological subject
27
- second_subject (AstrologicalSubject): Second astrological subject
28
- chart_name (str): Name of the composite chart. If None, it will be automatically generated.
60
+ Factory class to create composite astrological charts from two astrological subjects.
61
+
62
+ A composite chart represents the relationship between two people by calculating the midpoint
63
+ between corresponding planetary positions and house cusps. This creates a single chart
64
+ that symbolizes the energy of the relationship itself.
65
+
66
+ Currently supports the midpoint method for composite chart calculation, where:
67
+ - Planetary positions are calculated as the circular mean of corresponding planets
68
+ - House cusps are calculated as the circular mean of corresponding houses
69
+ - Houses are reordered to maintain consistency with the original house system
70
+ - Only common active points between both subjects are included
71
+
72
+ The resulting composite chart maintains the zodiac type, sidereal mode, houses system,
73
+ and perspective type of the input subjects (which must be identical between subjects).
74
+
75
+ Attributes:
76
+ model (CompositeSubjectModel | None): The generated composite subject model
77
+ first_subject (AstrologicalSubjectModel): First astrological subject
78
+ second_subject (AstrologicalSubjectModel): Second astrological subject
79
+ name (str): Name of the composite chart
80
+ composite_chart_type (CompositeChartType): Type of composite chart (currently "Midpoint")
81
+ zodiac_type (ZodiacType): Zodiac system used (Tropical or Sidereal)
82
+ sidereal_mode (SiderealMode | None): Sidereal calculation mode if applicable
83
+ houses_system_identifier (HousesSystemIdentifier): House system identifier
84
+ houses_system_name (str): Human-readable house system name
85
+ perspective_type (PerspectiveType): Astrological perspective type
86
+ houses_names_list (list[Houses]): List of house names
87
+ active_points (list[AstrologicalPoint]): Common active planetary points
88
+
89
+ Example:
90
+ >>> first_person = AstrologicalSubjectFactory.from_birth_data(
91
+ ... "John", 1990, 1, 1, 12, 0, "New York", "US"
92
+ ... )
93
+ >>> second_person = AstrologicalSubjectFactory.from_birth_data(
94
+ ... "Jane", 1992, 6, 15, 14, 30, "Los Angeles", "US"
95
+ ... )
96
+ >>> composite = CompositeSubjectFactory(first_person, second_person)
97
+ >>> composite_model = composite.get_midpoint_composite_subject_model()
98
+
99
+ Raises:
100
+ KerykeionException: When subjects have incompatible settings (different zodiac types,
101
+ sidereal modes, house systems, or perspective types)
29
102
  """
30
103
 
31
104
  model: Union[CompositeSubjectModel, None]
@@ -47,6 +120,27 @@ class CompositeSubjectFactory:
47
120
  second_subject: AstrologicalSubjectModel,
48
121
  chart_name: Union[str, None] = None
49
122
  ):
123
+ """
124
+ Initialize the composite subject factory with two astrological subjects.
125
+
126
+ Validates that both subjects have compatible settings and extracts common
127
+ active points for composite chart calculation.
128
+
129
+ Args:
130
+ first_subject (AstrologicalSubjectModel): First astrological subject for the composite
131
+ second_subject (AstrologicalSubjectModel): Second astrological subject for the composite
132
+ chart_name (str | None, optional): Custom name for the composite chart.
133
+ If None, generates name from subject names.
134
+ Defaults to None.
135
+
136
+ Raises:
137
+ KerykeionException: If subjects have different zodiac types, sidereal modes,
138
+ house systems, house system names, or perspective types.
139
+
140
+ Note:
141
+ Both subjects must have identical astrological calculation settings to ensure
142
+ meaningful composite chart calculations.
143
+ """
50
144
  self.model: Union[CompositeSubjectModel, None] = None
51
145
  self.composite_chart_type = "Midpoint"
52
146
 
@@ -102,30 +196,114 @@ class CompositeSubjectFactory:
102
196
  self.houses_names_list = self.first_subject.houses_names_list
103
197
 
104
198
  def __str__(self):
199
+ """
200
+ Return string representation of the composite subject.
201
+
202
+ Returns:
203
+ str: Human-readable string describing the composite chart.
204
+ """
105
205
  return f"Composite Chart Data for {self.name}"
106
206
 
107
207
  def __repr__(self):
208
+ """
209
+ Return detailed string representation of the composite subject.
210
+
211
+ Returns:
212
+ str: Detailed string representation for debugging purposes.
213
+ """
108
214
  return f"Composite Chart Data for {self.name}"
109
215
 
110
216
  def __eq__(self, other):
217
+ """
218
+ Check equality with another composite subject.
219
+
220
+ Args:
221
+ other (CompositeSubjectFactory): Another composite subject to compare with.
222
+
223
+ Returns:
224
+ bool: True if both subjects and chart name are identical.
225
+ """
111
226
  return self.first_subject == other.first_subject and self.second_subject == other.second_subject and self.name == other.chart_name
112
227
 
113
228
  def __ne__(self, other):
229
+ """
230
+ Check inequality with another composite subject.
231
+
232
+ Args:
233
+ other (CompositeSubjectFactory): Another composite subject to compare with.
234
+
235
+ Returns:
236
+ bool: True if subjects or chart name are different.
237
+ """
114
238
  return not self.__eq__(other)
115
239
 
116
240
  def __hash__(self):
241
+ """
242
+ Generate hash for the composite subject.
243
+
244
+ Returns:
245
+ int: Hash value based on both subjects and chart name.
246
+ """
117
247
  return hash((self.first_subject, self.second_subject, self.name))
118
248
 
119
249
  def __copy__(self):
250
+ """
251
+ Create a shallow copy of the composite subject.
252
+
253
+ Returns:
254
+ CompositeSubjectFactory: New instance with the same subjects and name.
255
+ """
120
256
  return CompositeSubjectFactory(self.first_subject, self.second_subject, self.name)
121
257
 
122
258
  def __setitem__(self, key, value):
259
+ """
260
+ Set an attribute using dictionary-style access.
261
+
262
+ Args:
263
+ key (str): Attribute name to set.
264
+ value: Value to assign to the attribute.
265
+ """
123
266
  setattr(self, key, value)
124
267
 
125
268
  def __getitem__(self, key):
269
+ """
270
+ Get an attribute using dictionary-style access.
271
+
272
+ Args:
273
+ key (str): Attribute name to retrieve.
274
+
275
+ Returns:
276
+ Any: Value of the requested attribute.
277
+
278
+ Raises:
279
+ AttributeError: If the attribute doesn't exist.
280
+ """
126
281
  return getattr(self, key)
127
282
 
128
283
  def _calculate_midpoint_composite_points_and_houses(self):
284
+ """
285
+ Calculate midpoint positions for all planets and house cusps in the composite chart.
286
+
287
+ This method implements the midpoint composite technique by:
288
+ 1. Computing circular means of house cusp positions from both subjects
289
+ 2. Sorting house positions to maintain proper house order
290
+ 3. Creating composite house cusps with calculated positions
291
+ 4. Computing circular means of planetary positions for common active points
292
+ 5. Assigning planets to their appropriate houses in the composite chart
293
+
294
+ The circular mean calculation ensures proper handling of zodiacal positions
295
+ around the 360-degree boundary (e.g., when one position is at 350° and
296
+ another at 10°, the midpoint is correctly calculated as 0°).
297
+
298
+ Side Effects:
299
+ - Updates instance attributes with calculated house cusp positions
300
+ - Updates instance attributes with calculated planetary positions
301
+ - Sets house assignments for each planetary position
302
+
303
+ Note:
304
+ This is an internal method called by get_midpoint_composite_subject_model().
305
+ Only planets that exist in both subjects' active_points are included.
306
+ """
129
307
  # Houses
130
308
  house_degree_list_ut = []
131
309
  for house in self.first_subject.houses_names_list:
@@ -165,12 +343,53 @@ class CompositeSubjectFactory:
165
343
  self[planet_lower]["house"] = get_planet_house(self[planet_lower]['abs_pos'], house_degree_list_ut)
166
344
 
167
345
  def _calculate_composite_lunar_phase(self):
346
+ """
347
+ Calculate the lunar phase for the composite chart based on Sun-Moon midpoints.
348
+
349
+ Uses the composite positions of the Sun and Moon to determine the lunar phase
350
+ angle, representing the relationship's emotional and instinctual dynamics.
351
+
352
+ Side Effects:
353
+ Sets the lunar_phase attribute with the calculated phase information.
354
+
355
+ Note:
356
+ This method should be called after _calculate_midpoint_composite_points_and_houses()
357
+ to ensure Sun and Moon composite positions are available.
358
+ """
168
359
  self.lunar_phase = calculate_moon_phase(
169
360
  self['moon'].abs_pos,
170
361
  self['sun'].abs_pos
171
362
  )
172
363
 
173
364
  def get_midpoint_composite_subject_model(self):
365
+ """
366
+ Generate the complete composite chart model using the midpoint technique.
367
+
368
+ This is the main public method for creating a composite chart. It orchestrates
369
+ the calculation of all composite positions and creates a complete CompositeSubjectModel
370
+ containing all necessary astrological data for the relationship chart.
371
+
372
+ The process includes:
373
+ 1. Calculating midpoint positions for all planets and house cusps
374
+ 2. Computing the composite lunar phase
375
+ 3. Assembling all data into a comprehensive model
376
+
377
+ Returns:
378
+ CompositeSubjectModel: Complete composite chart data model containing:
379
+ - All calculated planetary positions and their house placements
380
+ - House cusp positions maintaining proper house system order
381
+ - Lunar phase information for the composite chart
382
+ - All metadata from the original subjects (names, chart type, etc.)
383
+
384
+ Example:
385
+ >>> composite = CompositeSubjectFactory(person1, person2, "Our Relationship")
386
+ >>> model = composite.get_midpoint_composite_subject_model()
387
+ >>> print(f"Composite Sun at {model.sun.abs_pos}° in House {model.sun.house}")
388
+
389
+ Note:
390
+ This method performs all calculations internally and returns a complete,
391
+ ready-to-use composite chart model suitable for analysis or chart drawing.
392
+ """
174
393
  self._calculate_midpoint_composite_points_and_houses()
175
394
  self._calculate_composite_lunar_phase()
176
395