kerykeion 5.0.0a12__py3-none-any.whl → 5.0.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kerykeion might be problematic. Click here for more details.
- kerykeion/__init__.py +30 -6
- kerykeion/aspects/aspects_factory.py +40 -24
- kerykeion/aspects/aspects_utils.py +75 -6
- kerykeion/astrological_subject_factory.py +377 -226
- kerykeion/backword.py +680 -0
- kerykeion/chart_data_factory.py +484 -0
- kerykeion/charts/{kerykeion_chart_svg.py → chart_drawer.py} +612 -438
- kerykeion/charts/charts_utils.py +135 -94
- kerykeion/charts/draw_planets.py +38 -28
- kerykeion/charts/templates/aspect_grid_only.xml +188 -17
- kerykeion/charts/templates/chart.xml +104 -28
- kerykeion/charts/templates/wheel_only.xml +195 -24
- kerykeion/charts/themes/classic.css +11 -0
- kerykeion/charts/themes/dark-high-contrast.css +11 -0
- kerykeion/charts/themes/dark.css +11 -0
- kerykeion/charts/themes/light.css +11 -0
- kerykeion/charts/themes/strawberry.css +10 -0
- kerykeion/composite_subject_factory.py +4 -4
- kerykeion/ephemeris_data_factory.py +12 -9
- kerykeion/house_comparison/__init__.py +0 -3
- kerykeion/house_comparison/house_comparison_factory.py +3 -3
- kerykeion/house_comparison/house_comparison_utils.py +3 -4
- kerykeion/planetary_return_factory.py +8 -4
- kerykeion/relationship_score_factory.py +3 -3
- kerykeion/report.py +748 -67
- kerykeion/{kr_types → schemas}/__init__.py +44 -4
- kerykeion/schemas/chart_template_model.py +340 -0
- kerykeion/{kr_types → schemas}/kr_literals.py +7 -3
- kerykeion/{kr_types → schemas}/kr_models.py +220 -11
- kerykeion/{kr_types → schemas}/settings_models.py +7 -7
- kerykeion/settings/config_constants.py +75 -8
- kerykeion/settings/kerykeion_settings.py +1 -1
- kerykeion/settings/kr.config.json +130 -40
- kerykeion/settings/legacy/legacy_celestial_points_settings.py +8 -8
- kerykeion/sweph/ast136/s136108s.se1 +0 -0
- kerykeion/sweph/ast136/s136199s.se1 +0 -0
- kerykeion/sweph/ast136/s136472s.se1 +0 -0
- kerykeion/sweph/ast28/se28978s.se1 +0 -0
- kerykeion/sweph/ast50/se50000s.se1 +0 -0
- kerykeion/sweph/ast90/se90377s.se1 +0 -0
- kerykeion/sweph/ast90/se90482s.se1 +0 -0
- kerykeion/transits_time_range_factory.py +7 -7
- kerykeion/utilities.py +61 -38
- {kerykeion-5.0.0a12.dist-info → kerykeion-5.0.0b1.dist-info}/METADATA +507 -120
- kerykeion-5.0.0b1.dist-info/RECORD +58 -0
- kerykeion/house_comparison/house_comparison_models.py +0 -76
- kerykeion/kr_types/chart_types.py +0 -106
- kerykeion-5.0.0a12.dist-info/RECORD +0 -50
- /kerykeion/{kr_types → schemas}/kerykeion_exception.py +0 -0
- {kerykeion-5.0.0a12.dist-info → kerykeion-5.0.0b1.dist-info}/WHEEL +0 -0
- {kerykeion-5.0.0a12.dist-info → kerykeion-5.0.0b1.dist-info}/licenses/LICENSE +0 -0
kerykeion/__init__.py
CHANGED
|
@@ -8,31 +8,55 @@ This is part of Kerykeion (C) 2025 Giacomo Battaglia
|
|
|
8
8
|
# Local
|
|
9
9
|
from .aspects import AspectsFactory
|
|
10
10
|
from .astrological_subject_factory import AstrologicalSubjectFactory
|
|
11
|
-
from .
|
|
11
|
+
from .chart_data_factory import ChartDataFactory
|
|
12
|
+
from .schemas import KerykeionException
|
|
13
|
+
from .schemas.kr_models import (
|
|
14
|
+
ChartDataModel,
|
|
15
|
+
SingleChartDataModel,
|
|
16
|
+
DualChartDataModel,
|
|
17
|
+
ElementDistributionModel,
|
|
18
|
+
QualityDistributionModel,
|
|
19
|
+
HouseComparisonModel,
|
|
20
|
+
)
|
|
21
|
+
from .charts.chart_drawer import ChartDrawer
|
|
12
22
|
from .composite_subject_factory import CompositeSubjectFactory
|
|
13
23
|
from .ephemeris_data_factory import EphemerisDataFactory
|
|
14
24
|
from .house_comparison.house_comparison_factory import HouseComparisonFactory
|
|
15
|
-
from .house_comparison.house_comparison_models import HouseComparisonModel
|
|
16
|
-
from .kr_types import *
|
|
17
25
|
from .planetary_return_factory import PlanetaryReturnFactory, PlanetReturnModel
|
|
18
26
|
from .relationship_score_factory import RelationshipScoreFactory
|
|
19
|
-
from .report import
|
|
27
|
+
from .report import ReportGenerator
|
|
20
28
|
from .settings import KerykeionSettingsModel, get_settings
|
|
21
29
|
from .transits_time_range_factory import TransitsTimeRangeFactory
|
|
30
|
+
from .backword import (
|
|
31
|
+
AstrologicalSubject, # Legacy wrapper
|
|
32
|
+
KerykeionChartSVG, # Legacy wrapper
|
|
33
|
+
SynastryAspects, # Legacy wrapper
|
|
34
|
+
)
|
|
22
35
|
|
|
23
36
|
__all__ = [
|
|
24
37
|
"AspectsFactory",
|
|
25
38
|
"AstrologicalSubjectFactory",
|
|
26
|
-
"
|
|
39
|
+
"ChartDataFactory",
|
|
40
|
+
"ChartDataModel",
|
|
41
|
+
"SingleChartDataModel",
|
|
42
|
+
"DualChartDataModel",
|
|
43
|
+
"ElementDistributionModel",
|
|
44
|
+
"QualityDistributionModel",
|
|
45
|
+
"ChartDrawer",
|
|
27
46
|
"CompositeSubjectFactory",
|
|
28
47
|
"EphemerisDataFactory",
|
|
29
48
|
"HouseComparisonFactory",
|
|
30
49
|
"HouseComparisonModel",
|
|
50
|
+
"KerykeionException",
|
|
31
51
|
"PlanetaryReturnFactory",
|
|
32
52
|
"PlanetReturnModel",
|
|
33
53
|
"RelationshipScoreFactory",
|
|
34
|
-
"
|
|
54
|
+
"ReportGenerator",
|
|
35
55
|
"KerykeionSettingsModel",
|
|
36
56
|
"get_settings",
|
|
37
57
|
"TransitsTimeRangeFactory",
|
|
58
|
+
# Legacy (v4) exported names for backward compatibility
|
|
59
|
+
"AstrologicalSubject",
|
|
60
|
+
"KerykeionChartSVG",
|
|
61
|
+
"SynastryAspects",
|
|
38
62
|
]
|
|
@@ -7,20 +7,20 @@ import logging
|
|
|
7
7
|
from typing import Union, List, Optional
|
|
8
8
|
|
|
9
9
|
from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
|
|
10
|
-
from kerykeion.aspects.aspects_utils import get_aspect_from_two_points, get_active_points_list
|
|
11
|
-
from kerykeion.
|
|
12
|
-
AstrologicalSubjectModel,
|
|
13
|
-
AspectModel,
|
|
14
|
-
ActiveAspect,
|
|
15
|
-
CompositeSubjectModel,
|
|
16
|
-
PlanetReturnModel,
|
|
10
|
+
from kerykeion.aspects.aspects_utils import get_aspect_from_two_points, get_active_points_list, calculate_aspect_movement
|
|
11
|
+
from kerykeion.schemas.kr_models import (
|
|
12
|
+
AstrologicalSubjectModel,
|
|
13
|
+
AspectModel,
|
|
14
|
+
ActiveAspect,
|
|
15
|
+
CompositeSubjectModel,
|
|
16
|
+
PlanetReturnModel,
|
|
17
17
|
SingleChartAspectsModel,
|
|
18
18
|
DualChartAspectsModel,
|
|
19
19
|
# Legacy aliases for backward compatibility
|
|
20
20
|
NatalAspectsModel,
|
|
21
21
|
SynastryAspectsModel
|
|
22
22
|
)
|
|
23
|
-
from kerykeion.
|
|
23
|
+
from kerykeion.schemas.kr_literals import AstrologicalPoint
|
|
24
24
|
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_ASPECTS, DEFAULT_AXIS_ORBIT
|
|
25
25
|
from kerykeion.settings.legacy.legacy_celestial_points_settings import DEFAULT_CELESTIAL_POINTS_SETTINGS
|
|
26
26
|
from kerykeion.settings.legacy.legacy_chart_aspects_settings import DEFAULT_CHART_ASPECTS_SETTINGS
|
|
@@ -39,8 +39,8 @@ class AspectsFactory:
|
|
|
39
39
|
"""
|
|
40
40
|
Unified factory class for creating both single chart and dual chart aspects analysis.
|
|
41
41
|
|
|
42
|
-
This factory provides methods to calculate all aspects within a single chart or
|
|
43
|
-
between two charts. It consolidates the common functionality between different
|
|
42
|
+
This factory provides methods to calculate all aspects within a single chart or
|
|
43
|
+
between two charts. It consolidates the common functionality between different
|
|
44
44
|
types of aspect calculations while providing specialized methods for each type.
|
|
45
45
|
|
|
46
46
|
The factory provides both comprehensive and filtered aspect lists based on orb settings
|
|
@@ -57,7 +57,7 @@ class AspectsFactory:
|
|
|
57
57
|
>>> # For single chart aspects (natal, returns, etc.)
|
|
58
58
|
>>> johnny = AstrologicalSubjectFactory.from_birth_data("Johnny", 1963, 6, 9, 0, 0, "Owensboro", "US")
|
|
59
59
|
>>> single_chart_aspects = AspectsFactory.single_chart_aspects(johnny)
|
|
60
|
-
>>>
|
|
60
|
+
>>>
|
|
61
61
|
>>> # For dual chart aspects (synastry, comparisons, etc.)
|
|
62
62
|
>>> john = AstrologicalSubjectFactory.from_birth_data("John", 1990, 1, 1, 12, 0, "London", "GB")
|
|
63
63
|
>>> jane = AstrologicalSubjectFactory.from_birth_data("Jane", 1992, 6, 15, 14, 30, "Paris", "FR")
|
|
@@ -77,7 +77,7 @@ class AspectsFactory:
|
|
|
77
77
|
This method calculates all astrological aspects (angular relationships)
|
|
78
78
|
within a single chart. Can be used for any type of chart including:
|
|
79
79
|
- Natal charts
|
|
80
|
-
- Planetary return charts
|
|
80
|
+
- Planetary return charts
|
|
81
81
|
- Composite charts
|
|
82
82
|
- Any other single chart type
|
|
83
83
|
|
|
@@ -227,7 +227,7 @@ class AspectsFactory:
|
|
|
227
227
|
|
|
228
228
|
Args:
|
|
229
229
|
first_subject: First astrological subject
|
|
230
|
-
second_subject: Second astrological subject
|
|
230
|
+
second_subject: Second astrological subject
|
|
231
231
|
active_points_resolved: Resolved list of active celestial points
|
|
232
232
|
active_aspects_resolved: Resolved list of active aspects with orbs
|
|
233
233
|
aspects_settings: Chart aspect configuration settings
|
|
@@ -284,10 +284,10 @@ class AspectsFactory:
|
|
|
284
284
|
("Descendant", "Ascendant"),
|
|
285
285
|
("Medium_Coeli", "Imum_Coeli"),
|
|
286
286
|
("Imum_Coeli", "Medium_Coeli"),
|
|
287
|
-
("
|
|
288
|
-
("
|
|
289
|
-
("
|
|
290
|
-
("
|
|
287
|
+
("True_North_Lunar_Node", "True_South_Lunar_Node"),
|
|
288
|
+
("Mean_North_Lunar_Node", "Mean_South_Lunar_Node"),
|
|
289
|
+
("True_South_Lunar_Node", "True_North_Lunar_Node"),
|
|
290
|
+
("Mean_South_Lunar_Node", "Mean_North_Lunar_Node"),
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
all_aspects_list = []
|
|
@@ -313,6 +313,13 @@ class AspectsFactory:
|
|
|
313
313
|
first_planet_id = planet_id_lookup.get(first_name, 0)
|
|
314
314
|
second_planet_id = planet_id_lookup.get(second_name, 0)
|
|
315
315
|
|
|
316
|
+
# Calculate aspect movement (applying/separating/exact)
|
|
317
|
+
aspect_movement = calculate_aspect_movement(
|
|
318
|
+
active_points_list[first]["abs_pos"],
|
|
319
|
+
active_points_list[second]["abs_pos"],
|
|
320
|
+
aspect["aspect_degrees"]
|
|
321
|
+
)
|
|
322
|
+
|
|
316
323
|
aspect_model = AspectModel(
|
|
317
324
|
p1_name=first_name,
|
|
318
325
|
p1_owner=subject.name,
|
|
@@ -326,6 +333,7 @@ class AspectsFactory:
|
|
|
326
333
|
diff=aspect["diff"],
|
|
327
334
|
p1=first_planet_id,
|
|
328
335
|
p2=second_planet_id,
|
|
336
|
+
aspect_movement=aspect_movement,
|
|
329
337
|
)
|
|
330
338
|
all_aspects_list.append(aspect_model)
|
|
331
339
|
|
|
@@ -382,11 +390,18 @@ class AspectsFactory:
|
|
|
382
390
|
if aspect["verdict"]:
|
|
383
391
|
first_name = first_active_points_list[first]["name"]
|
|
384
392
|
second_name = second_active_points_list[second]["name"]
|
|
385
|
-
|
|
393
|
+
|
|
386
394
|
# Get planet IDs using lookup dictionary for better performance
|
|
387
395
|
first_planet_id = planet_id_lookup.get(first_name, 0)
|
|
388
396
|
second_planet_id = planet_id_lookup.get(second_name, 0)
|
|
389
397
|
|
|
398
|
+
# Calculate aspect movement (applying/separating/exact)
|
|
399
|
+
aspect_movement = calculate_aspect_movement(
|
|
400
|
+
first_active_points_list[first]["abs_pos"],
|
|
401
|
+
second_active_points_list[second]["abs_pos"],
|
|
402
|
+
aspect["aspect_degrees"]
|
|
403
|
+
)
|
|
404
|
+
|
|
390
405
|
aspect_model = AspectModel(
|
|
391
406
|
p1_name=first_name,
|
|
392
407
|
p1_owner=first_subject.name,
|
|
@@ -400,6 +415,7 @@ class AspectsFactory:
|
|
|
400
415
|
diff=aspect["diff"],
|
|
401
416
|
p1=first_planet_id,
|
|
402
417
|
p2=second_planet_id,
|
|
418
|
+
aspect_movement=aspect_movement,
|
|
403
419
|
)
|
|
404
420
|
all_aspects_list.append(aspect_model)
|
|
405
421
|
|
|
@@ -407,18 +423,18 @@ class AspectsFactory:
|
|
|
407
423
|
|
|
408
424
|
@staticmethod
|
|
409
425
|
def _update_aspect_settings(
|
|
410
|
-
aspects_settings: List[dict],
|
|
426
|
+
aspects_settings: List[dict],
|
|
411
427
|
active_aspects: List[ActiveAspect]
|
|
412
428
|
) -> List[dict]:
|
|
413
429
|
"""
|
|
414
430
|
Update aspects settings with active aspects orbs.
|
|
415
|
-
|
|
431
|
+
|
|
416
432
|
This is a common utility method used by both single chart and dual chart calculations.
|
|
417
|
-
|
|
433
|
+
|
|
418
434
|
Args:
|
|
419
435
|
aspects_settings: Base aspect settings
|
|
420
436
|
active_aspects: Active aspects with their orb configurations
|
|
421
|
-
|
|
437
|
+
|
|
422
438
|
Returns:
|
|
423
439
|
List of filtered and updated aspect settings
|
|
424
440
|
"""
|
|
@@ -472,7 +488,7 @@ class AspectsFactory:
|
|
|
472
488
|
) -> NatalAspectsModel:
|
|
473
489
|
"""
|
|
474
490
|
Legacy method - use single_chart_aspects() instead.
|
|
475
|
-
|
|
491
|
+
|
|
476
492
|
⚠️ DEPRECATION WARNING ⚠️
|
|
477
493
|
This method is deprecated. Use AspectsFactory.single_chart_aspects() instead.
|
|
478
494
|
"""
|
|
@@ -488,7 +504,7 @@ class AspectsFactory:
|
|
|
488
504
|
) -> SynastryAspectsModel:
|
|
489
505
|
"""
|
|
490
506
|
Legacy method - use dual_chart_aspects() instead.
|
|
491
|
-
|
|
507
|
+
|
|
492
508
|
⚠️ DEPRECATION WARNING ⚠️
|
|
493
509
|
This method is deprecated. Use AspectsFactory.dual_chart_aspects() instead.
|
|
494
510
|
"""
|
|
@@ -5,15 +5,13 @@
|
|
|
5
5
|
# TODO: Better documentation and unit tests
|
|
6
6
|
|
|
7
7
|
from swisseph import difdeg2n
|
|
8
|
-
from typing import Union
|
|
9
|
-
from kerykeion.
|
|
10
|
-
from kerykeion.
|
|
8
|
+
from typing import Union
|
|
9
|
+
from kerykeion.schemas.kr_models import AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel
|
|
10
|
+
from kerykeion.schemas.kr_literals import AspectMovementType
|
|
11
|
+
from kerykeion.schemas.settings_models import KerykeionSettingsCelestialPointModel
|
|
11
12
|
from kerykeion.settings.legacy.legacy_celestial_points_settings import DEFAULT_CELESTIAL_POINTS_SETTINGS
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
pass
|
|
16
|
-
|
|
17
15
|
def get_aspect_from_two_points(
|
|
18
16
|
aspects_settings: Union[list[dict], list[dict]],
|
|
19
17
|
point_one: Union[float, int],
|
|
@@ -58,6 +56,77 @@ def get_aspect_from_two_points(
|
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
|
|
59
|
+
def calculate_aspect_movement(
|
|
60
|
+
point_one_abs_pos: float,
|
|
61
|
+
point_two_abs_pos: float,
|
|
62
|
+
aspect_degrees: int,
|
|
63
|
+
exact_orb_threshold: float = 0.05
|
|
64
|
+
) -> AspectMovementType:
|
|
65
|
+
"""
|
|
66
|
+
Calculate whether an aspect is applying, separating, or exact.
|
|
67
|
+
|
|
68
|
+
An aspect is:
|
|
69
|
+
- "Exact": When the orb is very tight (default < 0.17°)
|
|
70
|
+
- "Applying": When the faster planet is moving toward the exact aspect
|
|
71
|
+
- "Separating": When the faster planet is moving away from the exact aspect
|
|
72
|
+
|
|
73
|
+
For simplicity, we assume the first planet (p1) is faster than the second (p2).
|
|
74
|
+
This is generally true for:
|
|
75
|
+
- Moon vs outer planets
|
|
76
|
+
- Inner planets vs outer planets
|
|
77
|
+
- Transits (transiting planet vs natal planet)
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
point_one_abs_pos: Absolute position of first point (0-360°)
|
|
81
|
+
point_two_abs_pos: Absolute position of second point (0-360°)
|
|
82
|
+
aspect_degrees: The exact degree of the aspect (0, 60, 90, 120, 180, etc.)
|
|
83
|
+
exact_orb_threshold: Maximum orb to consider aspect "exact" (default 0.17°)
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
"Applying", "Separating", or "Exact"
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
>>> # Moon at 45° applying to Sun at 50° (conjunction at 0°/360°)
|
|
90
|
+
>>> calculate_aspect_movement(45, 50, 0)
|
|
91
|
+
'Applying'
|
|
92
|
+
>>> # Moon at 55° separating from Sun at 50° (conjunction)
|
|
93
|
+
>>> calculate_aspect_movement(55, 50, 0)
|
|
94
|
+
'Separating'
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
# Calculate the angular distance
|
|
98
|
+
distance = abs(difdeg2n(point_one_abs_pos, point_two_abs_pos))
|
|
99
|
+
orbit = abs(distance - aspect_degrees)
|
|
100
|
+
|
|
101
|
+
# Check if aspect is exact (within tight orb)
|
|
102
|
+
if orbit <= exact_orb_threshold:
|
|
103
|
+
return "Exact"
|
|
104
|
+
|
|
105
|
+
# Calculate if p1 is ahead or behind p2 relative to the aspect
|
|
106
|
+
# We need to determine the direction of movement
|
|
107
|
+
diff = difdeg2n(point_one_abs_pos, point_two_abs_pos)
|
|
108
|
+
|
|
109
|
+
# For conjunction (0°) or opposition (180°)
|
|
110
|
+
if aspect_degrees == 0 or aspect_degrees == 360:
|
|
111
|
+
# If p1 is behind p2 (negative diff), it's applying
|
|
112
|
+
# If p1 is ahead of p2 (positive diff), it's separating
|
|
113
|
+
return "Applying" if diff < 0 else "Separating"
|
|
114
|
+
|
|
115
|
+
elif aspect_degrees == 180:
|
|
116
|
+
# For opposition, the logic is reversed
|
|
117
|
+
return "Applying" if abs(diff) < 180 else "Separating"
|
|
118
|
+
|
|
119
|
+
else:
|
|
120
|
+
# For other aspects (60°, 90°, 120°, 150°)
|
|
121
|
+
# Check if the distance is increasing or decreasing
|
|
122
|
+
# If distance < aspect_degrees and diff < 0: applying
|
|
123
|
+
# If distance > aspect_degrees or diff > 0: separating
|
|
124
|
+
if abs(diff) < aspect_degrees:
|
|
125
|
+
return "Applying" if diff < 0 else "Separating"
|
|
126
|
+
else:
|
|
127
|
+
return "Separating" if diff > 0 else "Applying"
|
|
128
|
+
|
|
129
|
+
|
|
61
130
|
def planet_id_decoder(planets_settings: list[KerykeionSettingsCelestialPointModel], name: str) -> int:
|
|
62
131
|
"""
|
|
63
132
|
Check if the name of the planet is the same in the settings and return
|