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.

Files changed (51) hide show
  1. kerykeion/__init__.py +30 -6
  2. kerykeion/aspects/aspects_factory.py +40 -24
  3. kerykeion/aspects/aspects_utils.py +75 -6
  4. kerykeion/astrological_subject_factory.py +377 -226
  5. kerykeion/backword.py +680 -0
  6. kerykeion/chart_data_factory.py +484 -0
  7. kerykeion/charts/{kerykeion_chart_svg.py → chart_drawer.py} +612 -438
  8. kerykeion/charts/charts_utils.py +135 -94
  9. kerykeion/charts/draw_planets.py +38 -28
  10. kerykeion/charts/templates/aspect_grid_only.xml +188 -17
  11. kerykeion/charts/templates/chart.xml +104 -28
  12. kerykeion/charts/templates/wheel_only.xml +195 -24
  13. kerykeion/charts/themes/classic.css +11 -0
  14. kerykeion/charts/themes/dark-high-contrast.css +11 -0
  15. kerykeion/charts/themes/dark.css +11 -0
  16. kerykeion/charts/themes/light.css +11 -0
  17. kerykeion/charts/themes/strawberry.css +10 -0
  18. kerykeion/composite_subject_factory.py +4 -4
  19. kerykeion/ephemeris_data_factory.py +12 -9
  20. kerykeion/house_comparison/__init__.py +0 -3
  21. kerykeion/house_comparison/house_comparison_factory.py +3 -3
  22. kerykeion/house_comparison/house_comparison_utils.py +3 -4
  23. kerykeion/planetary_return_factory.py +8 -4
  24. kerykeion/relationship_score_factory.py +3 -3
  25. kerykeion/report.py +748 -67
  26. kerykeion/{kr_types → schemas}/__init__.py +44 -4
  27. kerykeion/schemas/chart_template_model.py +340 -0
  28. kerykeion/{kr_types → schemas}/kr_literals.py +7 -3
  29. kerykeion/{kr_types → schemas}/kr_models.py +220 -11
  30. kerykeion/{kr_types → schemas}/settings_models.py +7 -7
  31. kerykeion/settings/config_constants.py +75 -8
  32. kerykeion/settings/kerykeion_settings.py +1 -1
  33. kerykeion/settings/kr.config.json +130 -40
  34. kerykeion/settings/legacy/legacy_celestial_points_settings.py +8 -8
  35. kerykeion/sweph/ast136/s136108s.se1 +0 -0
  36. kerykeion/sweph/ast136/s136199s.se1 +0 -0
  37. kerykeion/sweph/ast136/s136472s.se1 +0 -0
  38. kerykeion/sweph/ast28/se28978s.se1 +0 -0
  39. kerykeion/sweph/ast50/se50000s.se1 +0 -0
  40. kerykeion/sweph/ast90/se90377s.se1 +0 -0
  41. kerykeion/sweph/ast90/se90482s.se1 +0 -0
  42. kerykeion/transits_time_range_factory.py +7 -7
  43. kerykeion/utilities.py +61 -38
  44. {kerykeion-5.0.0a12.dist-info → kerykeion-5.0.0b1.dist-info}/METADATA +507 -120
  45. kerykeion-5.0.0b1.dist-info/RECORD +58 -0
  46. kerykeion/house_comparison/house_comparison_models.py +0 -76
  47. kerykeion/kr_types/chart_types.py +0 -106
  48. kerykeion-5.0.0a12.dist-info/RECORD +0 -50
  49. /kerykeion/{kr_types → schemas}/kerykeion_exception.py +0 -0
  50. {kerykeion-5.0.0a12.dist-info → kerykeion-5.0.0b1.dist-info}/WHEEL +0 -0
  51. {kerykeion-5.0.0a12.dist-info → kerykeion-5.0.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -87,6 +87,15 @@
87
87
  "perspective_type": "Perspective",
88
88
  "location": "Location",
89
89
  "day_of_week": "Day of Week",
90
+ "weekdays": {
91
+ "Monday": "Monday",
92
+ "Tuesday": "Tuesday",
93
+ "Wednesday": "Wednesday",
94
+ "Thursday": "Thursday",
95
+ "Friday": "Friday",
96
+ "Saturday": "Saturday",
97
+ "Sunday": "Sunday"
98
+ },
90
99
  "elements": "Elements",
91
100
  "qualities": "Qualities",
92
101
  "cardinal": "Cardinal",
@@ -108,12 +117,12 @@
108
117
  "Medium_Coeli": "Mc",
109
118
  "Descendant": "Dsc",
110
119
  "Imum_Coeli": "Ic",
111
- "True_Node": "N. Node (T)",
112
- "Mean_Node": "N. Node (M)",
120
+ "True_North_Lunar_Node": "N. Node (T)",
121
+ "Mean_North_Lunar_Node": "N. Node (M)",
113
122
  "Chiron": "Chiron",
114
123
  "Mean_Lilith": "Lilith",
115
- "True_South_Node": "S. Node (T)",
116
- "Mean_South_Node": "S. Node (M)",
124
+ "True_South_Lunar_Node": "S. Node (T)",
125
+ "Mean_South_Lunar_Node": "S. Node (M)",
117
126
  "True_Lilith": "Lilith (T)",
118
127
  "Earth": "Earth",
119
128
  "Pholus": "Pholus",
@@ -225,6 +234,15 @@
225
234
  "perspective_type": "Perspective",
226
235
  "location": "Lieu",
227
236
  "day_of_week": "Jour de la semaine",
237
+ "weekdays": {
238
+ "Monday": "Lundi",
239
+ "Tuesday": "Mardi",
240
+ "Wednesday": "Mercredi",
241
+ "Thursday": "Jeudi",
242
+ "Friday": "Vendredi",
243
+ "Saturday": "Samedi",
244
+ "Sunday": "Dimanche"
245
+ },
228
246
  "elements": "Éléments",
229
247
  "qualities": "Qualités",
230
248
  "cardinal": "Cardinal",
@@ -246,10 +264,10 @@
246
264
  "Medium_Coeli": "Mc",
247
265
  "Descendant": "Dsc",
248
266
  "Imum_Coeli": "Ic",
249
- "True_Node": "Nœud N. (V)",
250
- "Mean_Node": "Nœud N. (M)",
251
- "True_South_Node": "Nœud S. (V)",
252
- "Mean_South_Node": "Nœud S. (M)",
267
+ "True_North_Lunar_Node": "Nœud N. (V)",
268
+ "Mean_North_Lunar_Node": "Nœud N. (M)",
269
+ "True_South_Lunar_Node": "Nœud S. (V)",
270
+ "Mean_South_Lunar_Node": "Nœud S. (M)",
253
271
  "Chiron": "Chiron",
254
272
  "Mean_Lilith": "Lilith",
255
273
  "True_Lilith": "Lilith (V)",
@@ -363,6 +381,15 @@
363
381
  "perspective_type": "Perspectiva",
364
382
  "location": "Localização",
365
383
  "day_of_week": "Dia da semana",
384
+ "weekdays": {
385
+ "Monday": "Segunda",
386
+ "Tuesday": "Terça",
387
+ "Wednesday": "Quarta",
388
+ "Thursday": "Quinta",
389
+ "Friday": "Sexta",
390
+ "Saturday": "Sábado",
391
+ "Sunday": "Domingo"
392
+ },
366
393
  "elements": "Elementos",
367
394
  "qualities": "Qualidades",
368
395
  "cardinal": "Cardinal",
@@ -384,10 +411,10 @@
384
411
  "Medium_Coeli": "Mc",
385
412
  "Descendant": "Dsc",
386
413
  "Imum_Coeli": "Ic",
387
- "True_Node": "Nodo N. (V)",
388
- "Mean_Node": "Nodo N. (M)",
389
- "True_South_Node": "Nodo S. (V)",
390
- "Mean_South_Node": "Nodo S. (M)",
414
+ "True_North_Lunar_Node": "Nodo N. (V)",
415
+ "Mean_North_Lunar_Node": "Nodo N. (M)",
416
+ "True_South_Lunar_Node": "Nodo S. (V)",
417
+ "Mean_South_Lunar_Node": "Nodo S. (M)",
391
418
  "Chiron": "Quíron",
392
419
  "Mean_Lilith": "Lilith",
393
420
  "True_Lilith": "Lilith (V)",
@@ -501,6 +528,15 @@
501
528
  "perspective_type": "Prospettiva",
502
529
  "location": "Località",
503
530
  "day_of_week": "Giorno della settimana",
531
+ "weekdays": {
532
+ "Monday": "Lunedì",
533
+ "Tuesday": "Martedì",
534
+ "Wednesday": "Mercoledì",
535
+ "Thursday": "Giovedì",
536
+ "Friday": "Venerdì",
537
+ "Saturday": "Sabato",
538
+ "Sunday": "Domenica"
539
+ },
504
540
  "elements": "Elementi",
505
541
  "qualities": "Qualità",
506
542
  "cardinal": "Cardinale",
@@ -522,10 +558,10 @@
522
558
  "Medium_Coeli": "Mc",
523
559
  "Descendant": "Dsc",
524
560
  "Imum_Coeli": "Ic",
525
- "True_Node": "Nodo N. (V)",
526
- "Mean_Node": "Nodo N. (M)",
527
- "True_South_Node": "Nodo S. (V)",
528
- "Mean_South_Node": "Nodo S. (M)",
561
+ "True_North_Lunar_Node": "Nodo N. (V)",
562
+ "Mean_North_Lunar_Node": "Nodo N. (M)",
563
+ "True_South_Lunar_Node": "Nodo S. (V)",
564
+ "Mean_South_Lunar_Node": "Nodo S. (M)",
529
565
  "Chiron": "Chirone",
530
566
  "Mean_Lilith": "Lilith",
531
567
  "True_Lilith": "Lilith (V)",
@@ -639,6 +675,15 @@
639
675
  "perspective_type": "视角",
640
676
  "location": "位置",
641
677
  "day_of_week": "星期",
678
+ "weekdays": {
679
+ "Monday": "星期一",
680
+ "Tuesday": "星期二",
681
+ "Wednesday": "星期三",
682
+ "Thursday": "星期四",
683
+ "Friday": "星期五",
684
+ "Saturday": "星期六",
685
+ "Sunday": "星期日"
686
+ },
642
687
  "elements": "元素",
643
688
  "qualities": "性质",
644
689
  "cardinal": "本位",
@@ -660,10 +705,10 @@
660
705
  "Medium_Coeli": "上中天",
661
706
  "Descendant": "下降點",
662
707
  "Imum_Coeli": "下中天",
663
- "True_Node": "真北交点",
664
- "Mean_Node": "平均北交点",
665
- "True_South_Node": "真南交点",
666
- "Mean_South_Node": "平均南交点",
708
+ "True_North_Lunar_Node": "真北交点",
709
+ "Mean_North_Lunar_Node": "平均北交点",
710
+ "True_South_Lunar_Node": "真南交点",
711
+ "Mean_South_Lunar_Node": "平均南交点",
667
712
  "Chiron": "凱龍星",
668
713
  "Mean_Lilith": "黑月亮",
669
714
  "True_Lilith": "真黑月亮",
@@ -777,6 +822,15 @@
777
822
  "perspective_type": "Perspectiva",
778
823
  "location": "Ubicación",
779
824
  "day_of_week": "Día de la semana",
825
+ "weekdays": {
826
+ "Monday": "Lunes",
827
+ "Tuesday": "Martes",
828
+ "Wednesday": "Miércoles",
829
+ "Thursday": "Jueves",
830
+ "Friday": "Viernes",
831
+ "Saturday": "Sábado",
832
+ "Sunday": "Domingo"
833
+ },
780
834
  "elements": "Elementos",
781
835
  "qualities": "Cualidades",
782
836
  "cardinal": "Cardinal",
@@ -798,10 +852,10 @@
798
852
  "Medium_Coeli": "Mc",
799
853
  "Descendant": "Dsc",
800
854
  "Imum_Coeli": "Ic",
801
- "True_Node": "Nodo N. (V)",
802
- "Mean_Node": "Nodo N. (M)",
803
- "True_South_Node": "Nodo S. (V)",
804
- "Mean_South_Node": "Nodo S. (M)",
855
+ "True_North_Lunar_Node": "Nodo N. (V)",
856
+ "Mean_North_Lunar_Node": "Nodo N. (M)",
857
+ "True_South_Lunar_Node": "Nodo S. (V)",
858
+ "Mean_South_Lunar_Node": "Nodo S. (M)",
805
859
  "Chiron": "Quirón",
806
860
  "Mean_Lilith": "Lilith",
807
861
  "True_Lilith": "Lilith (V)",
@@ -915,6 +969,15 @@
915
969
  "perspective_type": "Перспектива",
916
970
  "location": "Местоположение",
917
971
  "day_of_week": "День недели",
972
+ "weekdays": {
973
+ "Monday": "Понедельник",
974
+ "Tuesday": "Вторник",
975
+ "Wednesday": "Среда",
976
+ "Thursday": "Четверг",
977
+ "Friday": "Пятница",
978
+ "Saturday": "Суббота",
979
+ "Sunday": "Воскресенье"
980
+ },
918
981
  "elements": "Стихии",
919
982
  "qualities": "Качества",
920
983
  "cardinal": "Кардинальный",
@@ -936,10 +999,10 @@
936
999
  "Medium_Coeli": "MC",
937
1000
  "Descendant": "ДСЦ",
938
1001
  "Imum_Coeli": "IC",
939
- "True_Node": "С. Узел (И)",
940
- "Mean_Node": "С. Узел (С)",
941
- "True_South_Node": "Ю. Узел (И)",
942
- "Mean_South_Node": "Ю. Узел (С)",
1002
+ "True_North_Lunar_Node": "С. Узел (И)",
1003
+ "Mean_North_Lunar_Node": "С. Узел (С)",
1004
+ "True_South_Lunar_Node": "Ю. Узел (И)",
1005
+ "Mean_South_Lunar_Node": "Ю. Узел (С)",
943
1006
  "Chiron": "Хирон",
944
1007
  "Mean_Lilith": "Лилит",
945
1008
  "True_Lilith": "Лилит (И)",
@@ -1053,6 +1116,15 @@
1053
1116
  "perspective_type": "Perspektif",
1054
1117
  "location": "Konum",
1055
1118
  "day_of_week": "Haftanın günü",
1119
+ "weekdays": {
1120
+ "Monday": "Pazartesi",
1121
+ "Tuesday": "Salı",
1122
+ "Wednesday": "Çarşamba",
1123
+ "Thursday": "Perşembe",
1124
+ "Friday": "Cuma",
1125
+ "Saturday": "Cumartesi",
1126
+ "Sunday": "Pazar"
1127
+ },
1056
1128
  "elements": "Elementler",
1057
1129
  "qualities": "Nitelikler",
1058
1130
  "cardinal": "Kardinal",
@@ -1074,12 +1146,12 @@
1074
1146
  "Medium_Coeli": "MC",
1075
1147
  "Descendant": "İK",
1076
1148
  "Imum_Coeli": "IC",
1077
- "True_Node": "K. Düğümü (T)",
1078
- "Mean_Node": "K. Düğümü (M)",
1149
+ "True_North_Lunar_Node": "K. Düğümü (T)",
1150
+ "Mean_North_Lunar_Node": "K. Düğümü (M)",
1079
1151
  "Chiron": "Kiron",
1080
1152
  "Mean_Lilith": "Lilith",
1081
- "True_South_Node": "G. Düğümü (T)",
1082
- "Mean_South_Node": "G. Düğümü (M)",
1153
+ "True_South_Lunar_Node": "G. Düğümü (T)",
1154
+ "Mean_South_Lunar_Node": "G. Düğümü (M)",
1083
1155
  "True_Lilith": "Lilith (T)",
1084
1156
  "Earth": "Dünya",
1085
1157
  "Pholus": "Pholus",
@@ -1191,6 +1263,15 @@
1191
1263
  "perspective_type": "Perspektive",
1192
1264
  "location": "Ort",
1193
1265
  "day_of_week": "Wochentag",
1266
+ "weekdays": {
1267
+ "Monday": "Montag",
1268
+ "Tuesday": "Dienstag",
1269
+ "Wednesday": "Mittwoch",
1270
+ "Thursday": "Donnerstag",
1271
+ "Friday": "Freitag",
1272
+ "Saturday": "Samstag",
1273
+ "Sunday": "Sonntag"
1274
+ },
1194
1275
  "elements": "Elemente",
1195
1276
  "qualities": "Qualitäten",
1196
1277
  "cardinal": "Kardinal",
@@ -1212,10 +1293,10 @@
1212
1293
  "Medium_Coeli": "MC",
1213
1294
  "Descendant": "DSC",
1214
1295
  "Imum_Coeli": "IC",
1215
- "True_Node": "Nordknoten (T)",
1216
- "Mean_Node": "Nordknoten (M)",
1217
- "True_South_Node": "Südknoten (T)",
1218
- "Mean_South_Node": "Südknoten (M)",
1296
+ "True_North_Lunar_Node": "Nordknoten (T)",
1297
+ "Mean_North_Lunar_Node": "Nordknoten (M)",
1298
+ "True_South_Lunar_Node": "Südknoten (T)",
1299
+ "Mean_South_Lunar_Node": "Südknoten (M)",
1219
1300
  "Chiron": "Chiron",
1220
1301
  "Mean_Lilith": "Lilith",
1221
1302
  "True_Lilith": "Lilith (T)",
@@ -1329,6 +1410,15 @@
1329
1410
  "perspective_type": "दृष्टिकोण",
1330
1411
  "location": "स्थान",
1331
1412
  "day_of_week": "सप्ताह का दिन",
1413
+ "weekdays": {
1414
+ "Monday": "सोमवार",
1415
+ "Tuesday": "मंगलवार",
1416
+ "Wednesday": "बुधवार",
1417
+ "Thursday": "गुरुवार",
1418
+ "Friday": "शुक्रवार",
1419
+ "Saturday": "शनिवार",
1420
+ "Sunday": "रविवार"
1421
+ },
1332
1422
  "elements": "तत्व",
1333
1423
  "qualities": "गुण",
1334
1424
  "cardinal": "चल",
@@ -1350,10 +1440,10 @@
1350
1440
  "Medium_Coeli": "एमसी",
1351
1441
  "Descendant": "डीएससी",
1352
1442
  "Imum_Coeli": "आईसी",
1353
- "True_Node": "उत्तर नोड (T)",
1354
- "Mean_Node": "उत्तर नोड (M)",
1355
- "True_South_Node": "दक्षिण नोड (T)",
1356
- "Mean_South_Node": "दक्षिण नोड (M)",
1443
+ "True_North_Lunar_Node": "उत्तर नोड (T)",
1444
+ "Mean_North_Lunar_Node": "उत्तर नोड (M)",
1445
+ "True_South_Lunar_Node": "दक्षिण नोड (T)",
1446
+ "Mean_South_Lunar_Node": "दक्षिण नोड (M)",
1357
1447
  "Chiron": "किरोन",
1358
1448
  "Mean_Lilith": "लिलिथ",
1359
1449
  "True_Lilith": "लिलिथ (T)",
@@ -74,17 +74,17 @@ DEFAULT_CELESTIAL_POINTS_SETTINGS = [
74
74
  },
75
75
  {
76
76
  "id": 10,
77
- "name": "Mean_Node",
77
+ "name": "Mean_North_Lunar_Node",
78
78
  "color": "var(--kerykeion-chart-color-mean-node)",
79
79
  "element_points": 0,
80
- "label": "Mean_Node"
80
+ "label": "Mean_North_Lunar_Node"
81
81
  },
82
82
  {
83
83
  "id": 11,
84
- "name": "True_Node",
84
+ "name": "True_North_Lunar_Node",
85
85
  "color": "var(--kerykeion-chart-color-true-node)",
86
86
  "element_points": 0,
87
- "label": "True_Node"
87
+ "label": "True_North_Lunar_Node"
88
88
  },
89
89
  {
90
90
  "id": 12,
@@ -130,17 +130,17 @@ DEFAULT_CELESTIAL_POINTS_SETTINGS = [
130
130
  },
131
131
  {
132
132
  "id": 18,
133
- "name": "Mean_South_Node",
133
+ "name": "Mean_South_Lunar_Node",
134
134
  "color": "var(--kerykeion-chart-color-mean-node)",
135
135
  "element_points": 0,
136
- "label": "Mean_South_Node"
136
+ "label": "Mean_South_Lunar_Node"
137
137
  },
138
138
  {
139
139
  "id": 19,
140
- "name": "True_South_Node",
140
+ "name": "True_South_Lunar_Node",
141
141
  "color": "var(--kerykeion-chart-color-true-node)",
142
142
  "element_points": 0,
143
- "label": "True_South_Node"
143
+ "label": "True_South_Lunar_Node"
144
144
  },
145
145
  {
146
146
  "id": 20,
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -24,7 +24,7 @@ Dependencies:
24
24
  - kerykeion.AstrologicalSubjectFactory: For creating astrological subjects
25
25
  - kerykeion.aspects.AspectsFactory: For calculating angular relationships
26
26
  - kerykeion.ephemeris_data_factory: For generating time-series planetary positions
27
- - kerykeion.kr_types: For type definitions and model structures
27
+ - kerykeion.schemas: For type definitions and model structures
28
28
  - datetime: For date/time handling
29
29
 
30
30
  Example:
@@ -57,13 +57,13 @@ License: AGPL-3.0
57
57
 
58
58
  from typing import Union, List
59
59
  from datetime import datetime, timedelta
60
- from kerykeion.kr_types.kr_models import AstrologicalSubjectModel
60
+ from kerykeion.schemas.kr_models import AstrologicalSubjectModel
61
61
  from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
62
62
  from kerykeion.aspects import AspectsFactory
63
63
  from kerykeion.ephemeris_data_factory import EphemerisDataFactory
64
- from kerykeion.kr_types.kr_literals import AstrologicalPoint
65
- from kerykeion.kr_types.kr_models import ActiveAspect, TransitMomentModel, TransitsTimeRangeModel
66
- from kerykeion.kr_types.settings_models import KerykeionSettingsModel
64
+ from kerykeion.schemas.kr_literals import AstrologicalPoint
65
+ from kerykeion.schemas.kr_models import ActiveAspect, TransitMomentModel, TransitsTimeRangeModel
66
+ from kerykeion.schemas.settings_models import KerykeionSettingsModel
67
67
  from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS, DEFAULT_ACTIVE_ASPECTS
68
68
  from pathlib import Path
69
69
 
@@ -115,8 +115,8 @@ class TransitsTimeRangeFactory:
115
115
 
116
116
  Custom configuration:
117
117
 
118
- >>> from kerykeion.kr_types import AstrologicalPoint, ActiveAspect
119
- >>> custom_points = [AstrologicalPoint.SUN, AstrologicalPoint.MOON]
118
+ >>> from kerykeion.schemas import AstrologicalPoint, ActiveAspect
119
+ >>> custom_points = ["Sun", "Moon"]
120
120
  >>> custom_aspects = [ActiveAspect.CONJUNCTION, ActiveAspect.OPPOSITION]
121
121
  >>> factory = TransitsTimeRangeFactory(
122
122
  ... natal_chart, ephemeris_data,
kerykeion/utilities.py CHANGED
@@ -4,7 +4,7 @@ Copyright: (C) 2025 Kerykeion Project
4
4
  License: AGPL-3.0
5
5
  """
6
6
 
7
- from kerykeion.kr_types import (
7
+ from kerykeion.schemas import (
8
8
  KerykeionPointModel,
9
9
  KerykeionException,
10
10
  ZodiacSignModel,
@@ -13,16 +13,13 @@ from kerykeion.kr_types import (
13
13
  CompositeSubjectModel,
14
14
  PlanetReturnModel,
15
15
  )
16
- from kerykeion.kr_types.kr_literals import LunarPhaseEmoji, LunarPhaseName, PointType, AstrologicalPoint, Houses
17
- from typing import Union, get_args, TYPE_CHECKING
16
+ from kerykeion.schemas.kr_literals import LunarPhaseEmoji, LunarPhaseName, PointType, AstrologicalPoint, Houses
17
+ from typing import Union, Optional, get_args
18
18
  import logging
19
19
  import math
20
20
  import re
21
21
  from datetime import datetime
22
22
 
23
- if TYPE_CHECKING:
24
- pass
25
-
26
23
 
27
24
  def get_number_from_name(name: AstrologicalPoint) -> int:
28
25
  """
@@ -58,14 +55,14 @@ def get_number_from_name(name: AstrologicalPoint) -> int:
58
55
  return 8
59
56
  elif name == "Pluto":
60
57
  return 9
61
- elif name == "Mean_Node":
58
+ elif name == "Mean_North_Lunar_Node":
62
59
  return 10
63
- elif name == "True_Node":
60
+ elif name == "True_North_Lunar_Node":
64
61
  return 11
65
62
  # Note: Swiss ephemeris library has no constants for south nodes. We're using integers >= 1000 for them.
66
- elif name == "Mean_South_Node":
63
+ elif name == "Mean_South_Lunar_Node":
67
64
  return 1000
68
- elif name == "True_South_Node":
65
+ elif name == "True_South_Lunar_Node":
69
66
  return 1100
70
67
  elif name == "Chiron":
71
68
  return 15
@@ -84,7 +81,7 @@ def get_number_from_name(name: AstrologicalPoint) -> int:
84
81
 
85
82
 
86
83
  def get_kerykeion_point_from_degree(
87
- degree: Union[int, float], name: Union[AstrologicalPoint, Houses], point_type: PointType
84
+ degree: Union[int, float], name: Union[AstrologicalPoint, Houses], point_type: PointType, speed: Optional[float] = None, declination: Optional[float] = None
88
85
  ) -> KerykeionPointModel:
89
86
  """
90
87
  Create a KerykeionPointModel from a degree position.
@@ -93,6 +90,8 @@ def get_kerykeion_point_from_degree(
93
90
  degree: The degree position (0-360, negative values are converted to positive)
94
91
  name: The name of the celestial point or house
95
92
  point_type: The type classification of the point
93
+ speed: The velocity/speed of the celestial point in degrees per day (optional)
94
+ declination: The declination of the celestial point in degrees (optional)
96
95
 
97
96
  Returns:
98
97
  A KerykeionPointModel with calculated zodiac sign, position, and properties
@@ -136,6 +135,8 @@ def get_kerykeion_point_from_degree(
136
135
  abs_pos=degree,
137
136
  emoji=zodiac_sign.emoji,
138
137
  point_type=point_type,
138
+ speed=speed,
139
+ declination=declination,
139
140
  )
140
141
 
141
142
 
@@ -416,9 +417,6 @@ def calculate_moon_phase(moon_abs_pos: float, sun_abs_pos: float) -> LunarPhaseM
416
417
  Returns:
417
418
  LunarPhaseModel containing phase data, emoji, and name
418
419
  """
419
- # Initialize moon_phase and sun_phase to None in case of an error
420
- moon_phase, sun_phase = None, None
421
-
422
420
  # Calculate the anti-clockwise degrees between the sun and moon
423
421
  degrees_between = (moon_abs_pos - sun_abs_pos) % 360
424
422
 
@@ -426,30 +424,12 @@ def calculate_moon_phase(moon_abs_pos: float, sun_abs_pos: float) -> LunarPhaseM
426
424
  step = 360.0 / 28.0
427
425
  moon_phase = int(degrees_between // step) + 1
428
426
 
429
- # Define the sun phase steps
430
- sunstep = [
431
- 0, 30, 40, 50, 60, 70, 80, 90, 120, 130, 140, 150, 160, 170, 180,
432
- 210, 220, 230, 240, 250, 260, 270, 300, 310, 320, 330, 340, 350
433
- ]
434
-
435
- # Calculate the sun phase (1-28) based on the degrees between the sun and moon
436
- for x in range(len(sunstep)):
437
- low = sunstep[x]
438
- high = sunstep[x + 1] if x < len(sunstep) - 1 else 360
439
- if low <= degrees_between < high:
440
- sun_phase = x + 1
441
- break
442
-
443
- # Create a dictionary with the lunar phase information
444
- lunar_phase_dictionary = {
445
- "degrees_between_s_m": degrees_between,
446
- "moon_phase": moon_phase,
447
- "sun_phase": sun_phase,
448
- "moon_emoji": get_moon_emoji_from_phase_int(moon_phase),
449
- "moon_phase_name": get_moon_phase_name_from_phase_int(moon_phase),
450
- }
451
-
452
- return LunarPhaseModel(**lunar_phase_dictionary)
427
+ return LunarPhaseModel(
428
+ degrees_between_s_m=degrees_between,
429
+ moon_phase=moon_phase,
430
+ moon_emoji=get_moon_emoji_from_phase_int(moon_phase),
431
+ moon_phase_name=get_moon_phase_name_from_phase_int(moon_phase)
432
+ )
453
433
 
454
434
 
455
435
  def circular_sort(degrees: list[Union[int, float]]) -> list[Union[int, float]]:
@@ -751,3 +731,46 @@ def find_common_active_points(first_points: list[AstrologicalPoint], second_poin
751
731
  common_points = list(set(first_points) & set(second_points))
752
732
 
753
733
  return common_points
734
+
735
+
736
+ def distribute_percentages_to_100(values: dict[str, float]) -> dict[str, int]:
737
+ """
738
+ Distribute percentages so they sum to exactly 100.
739
+
740
+ This function uses a largest remainder method to ensure that
741
+ the percentage total equals 100 even after rounding.
742
+
743
+ Args:
744
+ values: Dictionary with keys and their raw percentage values
745
+
746
+ Returns:
747
+ Dictionary with the same keys and integer percentages that sum to 100
748
+ """
749
+ if not values:
750
+ return {}
751
+
752
+ total = sum(values.values())
753
+ if total == 0:
754
+ return {key: 0 for key in values.keys()}
755
+
756
+ # Calculate base percentages
757
+ percentages = {key: value * 100 / total for key, value in values.items()}
758
+
759
+ # Get integer parts and remainders
760
+ integer_parts = {key: int(value) for key, value in percentages.items()}
761
+ remainders = {key: percentages[key] - integer_parts[key] for key in percentages.keys()}
762
+
763
+ # Calculate how many we need to add to reach 100
764
+ current_sum = sum(integer_parts.values())
765
+ needed = 100 - current_sum
766
+
767
+ # Sort by remainder (largest first) and add 1 to the largest remainders
768
+ sorted_by_remainder = sorted(remainders.items(), key=lambda x: x[1], reverse=True)
769
+
770
+ result = integer_parts.copy()
771
+ for i in range(needed):
772
+ if i < len(sorted_by_remainder):
773
+ key = sorted_by_remainder[i][0]
774
+ result[key] += 1
775
+
776
+ return result