kerykeion 5.0.0b1__py3-none-any.whl → 5.0.0b4__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 (30) hide show
  1. kerykeion/__init__.py +3 -2
  2. kerykeion/aspects/aspects_factory.py +60 -21
  3. kerykeion/aspects/aspects_utils.py +1 -1
  4. kerykeion/backword.py +111 -18
  5. kerykeion/chart_data_factory.py +72 -7
  6. kerykeion/charts/chart_drawer.py +601 -206
  7. kerykeion/charts/charts_utils.py +440 -255
  8. kerykeion/charts/templates/aspect_grid_only.xml +269 -312
  9. kerykeion/charts/templates/chart.xml +302 -328
  10. kerykeion/charts/templates/wheel_only.xml +271 -312
  11. kerykeion/charts/themes/black-and-white.css +148 -0
  12. kerykeion/relationship_score_factory.py +12 -2
  13. kerykeion/schemas/chart_template_model.py +27 -0
  14. kerykeion/schemas/kr_literals.py +1 -1
  15. kerykeion/settings/__init__.py +16 -2
  16. kerykeion/settings/chart_defaults.py +444 -0
  17. kerykeion/settings/config_constants.py +0 -5
  18. kerykeion/settings/kerykeion_settings.py +31 -74
  19. kerykeion/settings/translation_strings.py +1479 -0
  20. kerykeion/settings/translations.py +74 -0
  21. kerykeion/transits_time_range_factory.py +10 -1
  22. {kerykeion-5.0.0b1.dist-info → kerykeion-5.0.0b4.dist-info}/METADATA +304 -204
  23. {kerykeion-5.0.0b1.dist-info → kerykeion-5.0.0b4.dist-info}/RECORD +25 -26
  24. kerykeion/settings/kr.config.json +0 -1474
  25. kerykeion/settings/legacy/__init__.py +0 -0
  26. kerykeion/settings/legacy/legacy_celestial_points_settings.py +0 -299
  27. kerykeion/settings/legacy/legacy_chart_aspects_settings.py +0 -71
  28. kerykeion/settings/legacy/legacy_color_settings.py +0 -42
  29. {kerykeion-5.0.0b1.dist-info → kerykeion-5.0.0b4.dist-info}/WHEEL +0 -0
  30. {kerykeion-5.0.0b1.dist-info → kerykeion-5.0.0b4.dist-info}/licenses/LICENSE +0 -0
kerykeion/__init__.py CHANGED
@@ -25,11 +25,12 @@ from .house_comparison.house_comparison_factory import HouseComparisonFactory
25
25
  from .planetary_return_factory import PlanetaryReturnFactory, PlanetReturnModel
26
26
  from .relationship_score_factory import RelationshipScoreFactory
27
27
  from .report import ReportGenerator
28
- from .settings import KerykeionSettingsModel, get_settings
28
+ from .settings import KerykeionSettingsModel
29
29
  from .transits_time_range_factory import TransitsTimeRangeFactory
30
30
  from .backword import (
31
31
  AstrologicalSubject, # Legacy wrapper
32
32
  KerykeionChartSVG, # Legacy wrapper
33
+ NatalAspects, # Legacy wrapper
33
34
  SynastryAspects, # Legacy wrapper
34
35
  )
35
36
 
@@ -53,10 +54,10 @@ __all__ = [
53
54
  "RelationshipScoreFactory",
54
55
  "ReportGenerator",
55
56
  "KerykeionSettingsModel",
56
- "get_settings",
57
57
  "TransitsTimeRangeFactory",
58
58
  # Legacy (v4) exported names for backward compatibility
59
59
  "AstrologicalSubject",
60
60
  "KerykeionChartSVG",
61
+ "NatalAspects",
61
62
  "SynastryAspects",
62
63
  ]
@@ -21,9 +21,11 @@ from kerykeion.schemas.kr_models import (
21
21
  SynastryAspectsModel
22
22
  )
23
23
  from kerykeion.schemas.kr_literals import AstrologicalPoint
24
- from kerykeion.settings.config_constants import DEFAULT_ACTIVE_ASPECTS, DEFAULT_AXIS_ORBIT
25
- from kerykeion.settings.legacy.legacy_celestial_points_settings import DEFAULT_CELESTIAL_POINTS_SETTINGS
26
- from kerykeion.settings.legacy.legacy_chart_aspects_settings import DEFAULT_CHART_ASPECTS_SETTINGS
24
+ from kerykeion.settings.config_constants import DEFAULT_ACTIVE_ASPECTS
25
+ from kerykeion.settings.chart_defaults import (
26
+ DEFAULT_CELESTIAL_POINTS_SETTINGS,
27
+ DEFAULT_CHART_ASPECTS_SETTINGS,
28
+ )
27
29
  from kerykeion.utilities import find_common_active_points
28
30
 
29
31
  # Axes constants for orb filtering
@@ -70,6 +72,7 @@ class AspectsFactory:
70
72
  *,
71
73
  active_points: Optional[List[AstrologicalPoint]] = None,
72
74
  active_aspects: Optional[List[ActiveAspect]] = None,
75
+ axis_orb_limit: Optional[float] = None,
73
76
  ) -> SingleChartAspectsModel:
74
77
  """
75
78
  Create aspects analysis for a single astrological chart.
@@ -87,6 +90,7 @@ class AspectsFactory:
87
90
  Kwargs:
88
91
  active_points: List of points to include in calculations
89
92
  active_aspects: List of aspects with their orb settings
93
+ axis_orb_limit: Optional orb threshold applied to chart axes; when None, no special axis filter
90
94
 
91
95
  Returns:
92
96
  SingleChartAspectsModel containing all calculated aspects data
@@ -99,8 +103,6 @@ class AspectsFactory:
99
103
  # Initialize settings and configurations
100
104
  celestial_points = DEFAULT_CELESTIAL_POINTS_SETTINGS
101
105
  aspects_settings = DEFAULT_CHART_ASPECTS_SETTINGS
102
- axes_orbit_settings = DEFAULT_AXIS_ORBIT
103
-
104
106
  # Set active aspects with default fallback
105
107
  active_aspects_resolved = active_aspects if active_aspects is not None else DEFAULT_ACTIVE_ASPECTS
106
108
 
@@ -114,8 +116,12 @@ class AspectsFactory:
114
116
  )
115
117
 
116
118
  return AspectsFactory._create_single_chart_aspects_model(
117
- subject, active_points_resolved, active_aspects_resolved,
118
- aspects_settings, axes_orbit_settings, celestial_points
119
+ subject,
120
+ active_points_resolved,
121
+ active_aspects_resolved,
122
+ aspects_settings,
123
+ axis_orb_limit,
124
+ celestial_points,
119
125
  )
120
126
 
121
127
  @staticmethod
@@ -125,6 +131,7 @@ class AspectsFactory:
125
131
  *,
126
132
  active_points: Optional[List[AstrologicalPoint]] = None,
127
133
  active_aspects: Optional[List[ActiveAspect]] = None,
134
+ axis_orb_limit: Optional[float] = None,
128
135
  ) -> DualChartAspectsModel:
129
136
  """
130
137
  Create aspects analysis between two astrological charts.
@@ -145,6 +152,7 @@ class AspectsFactory:
145
152
  If None, uses common points between both subjects.
146
153
  active_aspects: Optional list of aspect types with their orb settings.
147
154
  If None, uses default aspect configuration.
155
+ axis_orb_limit: Optional orb threshold for chart axes (applied to single chart calculations only)
148
156
 
149
157
  Returns:
150
158
  DualChartAspectsModel: Complete model containing all calculated aspects data,
@@ -159,8 +167,6 @@ class AspectsFactory:
159
167
  # Initialize settings and configurations
160
168
  celestial_points = DEFAULT_CELESTIAL_POINTS_SETTINGS
161
169
  aspects_settings = DEFAULT_CHART_ASPECTS_SETTINGS
162
- axes_orbit_settings = DEFAULT_AXIS_ORBIT
163
-
164
170
  # Set active aspects with default fallback
165
171
  active_aspects_resolved = active_aspects if active_aspects is not None else DEFAULT_ACTIVE_ASPECTS
166
172
 
@@ -180,8 +186,13 @@ class AspectsFactory:
180
186
  )
181
187
 
182
188
  return AspectsFactory._create_dual_chart_aspects_model(
183
- first_subject, second_subject, active_points_resolved, active_aspects_resolved,
184
- aspects_settings, axes_orbit_settings, celestial_points
189
+ first_subject,
190
+ second_subject,
191
+ active_points_resolved,
192
+ active_aspects_resolved,
193
+ aspects_settings,
194
+ axis_orb_limit,
195
+ celestial_points,
185
196
  )
186
197
 
187
198
  @staticmethod
@@ -190,7 +201,7 @@ class AspectsFactory:
190
201
  active_points_resolved: List[AstrologicalPoint],
191
202
  active_aspects_resolved: List[ActiveAspect],
192
203
  aspects_settings: List[dict],
193
- axes_orbit_settings: float,
204
+ axis_orb_limit: Optional[float],
194
205
  celestial_points: List[dict]
195
206
  ) -> SingleChartAspectsModel:
196
207
  """
@@ -202,7 +213,11 @@ class AspectsFactory:
202
213
  all_aspects = AspectsFactory._calculate_single_chart_aspects(
203
214
  subject, active_points_resolved, active_aspects_resolved, aspects_settings, celestial_points
204
215
  )
205
- relevant_aspects = AspectsFactory._filter_relevant_aspects(all_aspects, axes_orbit_settings)
216
+ relevant_aspects = AspectsFactory._filter_relevant_aspects(
217
+ all_aspects,
218
+ axis_orb_limit,
219
+ apply_axis_orb_filter=axis_orb_limit is not None,
220
+ )
206
221
 
207
222
  return SingleChartAspectsModel(
208
223
  subject=subject,
@@ -219,7 +234,7 @@ class AspectsFactory:
219
234
  active_points_resolved: List[AstrologicalPoint],
220
235
  active_aspects_resolved: List[ActiveAspect],
221
236
  aspects_settings: List[dict],
222
- axes_orbit_settings: float,
237
+ axis_orb_limit: Optional[float],
223
238
  celestial_points: List[dict]
224
239
  ) -> DualChartAspectsModel:
225
240
  """
@@ -231,7 +246,7 @@ class AspectsFactory:
231
246
  active_points_resolved: Resolved list of active celestial points
232
247
  active_aspects_resolved: Resolved list of active aspects with orbs
233
248
  aspects_settings: Chart aspect configuration settings
234
- axes_orbit_settings: Orb threshold for chart axes
249
+ axis_orb_limit: Orb threshold for chart axes
235
250
  celestial_points: Celestial points configuration
236
251
 
237
252
  Returns:
@@ -241,7 +256,11 @@ class AspectsFactory:
241
256
  first_subject, second_subject, active_points_resolved, active_aspects_resolved,
242
257
  aspects_settings, celestial_points
243
258
  )
244
- relevant_aspects = AspectsFactory._filter_relevant_aspects(all_aspects, axes_orbit_settings)
259
+ relevant_aspects = AspectsFactory._filter_relevant_aspects(
260
+ all_aspects,
261
+ axis_orb_limit,
262
+ apply_axis_orb_filter=False,
263
+ )
245
264
 
246
265
  return DualChartAspectsModel(
247
266
  first_subject=first_subject,
@@ -449,7 +468,12 @@ class AspectsFactory:
449
468
  return filtered_settings
450
469
 
451
470
  @staticmethod
452
- def _filter_relevant_aspects(all_aspects: List[AspectModel], axes_orbit_settings: float) -> List[AspectModel]:
471
+ def _filter_relevant_aspects(
472
+ all_aspects: List[AspectModel],
473
+ axis_orb_limit: Optional[float],
474
+ *,
475
+ apply_axis_orb_filter: bool,
476
+ ) -> List[AspectModel]:
453
477
  """
454
478
  Filter aspects based on orb thresholds for axes and comprehensive criteria.
455
479
 
@@ -458,7 +482,8 @@ class AspectsFactory:
458
482
 
459
483
  Args:
460
484
  all_aspects: Complete list of calculated aspects
461
- axes_orbit_settings: Orb threshold for axes aspects
485
+ axis_orb_limit: Optional orb threshold for axes aspects
486
+ apply_axis_orb_filter: Whether to apply the axis-specific orb filtering logic
462
487
 
463
488
  Returns:
464
489
  Filtered list of relevant aspects
@@ -467,11 +492,14 @@ class AspectsFactory:
467
492
 
468
493
  relevant_aspects = []
469
494
 
495
+ if not apply_axis_orb_filter or axis_orb_limit is None:
496
+ return list(all_aspects)
497
+
470
498
  for aspect in all_aspects:
471
499
  # Check if aspect involves any of the chart axes and apply stricter orb limits
472
500
  aspect_involves_axes = (aspect.p1_name in AXES_LIST or aspect.p2_name in AXES_LIST)
473
501
 
474
- if aspect_involves_axes and abs(aspect.orbit) >= axes_orbit_settings:
502
+ if aspect_involves_axes and abs(aspect.orbit) >= axis_orb_limit:
475
503
  continue
476
504
 
477
505
  relevant_aspects.append(aspect)
@@ -485,6 +513,7 @@ class AspectsFactory:
485
513
  *,
486
514
  active_points: Optional[List[AstrologicalPoint]] = None,
487
515
  active_aspects: Optional[List[ActiveAspect]] = None,
516
+ axis_orb_limit: Optional[float] = None,
488
517
  ) -> NatalAspectsModel:
489
518
  """
490
519
  Legacy method - use single_chart_aspects() instead.
@@ -492,7 +521,12 @@ class AspectsFactory:
492
521
  ⚠️ DEPRECATION WARNING ⚠️
493
522
  This method is deprecated. Use AspectsFactory.single_chart_aspects() instead.
494
523
  """
495
- return AspectsFactory.single_chart_aspects(subject, active_points=active_points, active_aspects=active_aspects)
524
+ return AspectsFactory.single_chart_aspects(
525
+ subject,
526
+ active_points=active_points,
527
+ active_aspects=active_aspects,
528
+ axis_orb_limit=axis_orb_limit,
529
+ )
496
530
 
497
531
  @staticmethod
498
532
  def synastry_aspects(
@@ -501,6 +535,7 @@ class AspectsFactory:
501
535
  *,
502
536
  active_points: Optional[List[AstrologicalPoint]] = None,
503
537
  active_aspects: Optional[List[ActiveAspect]] = None,
538
+ axis_orb_limit: Optional[float] = None,
504
539
  ) -> SynastryAspectsModel:
505
540
  """
506
541
  Legacy method - use dual_chart_aspects() instead.
@@ -509,7 +544,11 @@ class AspectsFactory:
509
544
  This method is deprecated. Use AspectsFactory.dual_chart_aspects() instead.
510
545
  """
511
546
  return AspectsFactory.dual_chart_aspects(
512
- first_subject, second_subject, active_points=active_points, active_aspects=active_aspects
547
+ first_subject,
548
+ second_subject,
549
+ active_points=active_points,
550
+ active_aspects=active_aspects,
551
+ axis_orb_limit=axis_orb_limit,
513
552
  )
514
553
 
515
554
 
@@ -9,7 +9,7 @@ from typing import Union
9
9
  from kerykeion.schemas.kr_models import AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel
10
10
  from kerykeion.schemas.kr_literals import AspectMovementType
11
11
  from kerykeion.schemas.settings_models import KerykeionSettingsCelestialPointModel
12
- from kerykeion.settings.legacy.legacy_celestial_points_settings import DEFAULT_CELESTIAL_POINTS_SETTINGS
12
+ from kerykeion.settings.chart_defaults import DEFAULT_CELESTIAL_POINTS_SETTINGS
13
13
 
14
14
 
15
15
  def get_aspect_from_two_points(
kerykeion/backword.py CHANGED
@@ -25,7 +25,7 @@ Note: This file name is intentionally spelled 'backword.py' per user request.
25
25
  """
26
26
  from __future__ import annotations
27
27
 
28
- from typing import Any, Iterable, List, Optional, Sequence, Union, Literal, cast
28
+ from typing import Any, Iterable, List, Mapping, Optional, Sequence, Union, Literal, cast
29
29
  import logging
30
30
  import warnings
31
31
  from datetime import datetime
@@ -51,7 +51,6 @@ from .schemas.kr_literals import (
51
51
  )
52
52
  from .schemas import ZodiacType, SiderealMode, HousesSystemIdentifier, PerspectiveType
53
53
  from pathlib import Path
54
- from .settings import KerykeionSettingsModel, get_settings
55
54
 
56
55
  # ---------------------------------------------------------------------------
57
56
  # Helpers
@@ -394,15 +393,25 @@ class KerykeionChartSVG:
394
393
  chart_type: ChartType = "Natal",
395
394
  second_obj: Union[AstrologicalSubject, AstrologicalSubjectModel, None] = None,
396
395
  new_output_directory: Union[str, None] = None,
397
- new_settings_file: Union[Path, None, KerykeionSettingsModel, dict] = None, # retained for signature compatibility (unused)
396
+ new_settings_file: Union[Path, None, dict] = None, # retained for signature compatibility (unused)
398
397
  theme: Union[KerykeionChartTheme, None] = "classic",
399
398
  double_chart_aspect_grid_type: Literal["list", "table"] = "list",
400
399
  chart_language: KerykeionChartLanguage = "EN",
401
400
  active_points: List[AstrologicalPoint] = DEFAULT_ACTIVE_POINTS, # type: ignore[assignment]
402
401
  active_aspects: Optional[List[ActiveAspect]] = None,
402
+ *,
403
+ language_pack: Optional[Mapping[str, Any]] = None,
404
+
403
405
  ) -> None:
404
406
  _deprecated("KerykeionChartSVG", "ChartDataFactory + ChartDrawer")
405
407
 
408
+ if new_settings_file is not None:
409
+ warnings.warn(
410
+ "'new_settings_file' is deprecated and ignored in Kerykeion v5. Use language_pack instead.",
411
+ DeprecationWarning,
412
+ stacklevel=2,
413
+ )
414
+
406
415
  if isinstance(first_obj, AstrologicalSubject):
407
416
  subject_model: Union[AstrologicalSubjectModel, CompositeSubjectModel] = first_obj.model()
408
417
  else:
@@ -419,7 +428,7 @@ class KerykeionChartSVG:
419
428
  active_aspects = list(active_aspects)
420
429
 
421
430
  self.chart_type = chart_type
422
- self.new_settings_file = new_settings_file
431
+ self.language_pack = language_pack
423
432
  self.theme = theme # type: ignore[assignment]
424
433
  self.double_chart_aspect_grid_type = double_chart_aspect_grid_type
425
434
  self.chart_language = chart_language # type: ignore[assignment]
@@ -516,10 +525,10 @@ class KerykeionChartSVG:
516
525
  self.chart_data = data
517
526
  self._chart_drawer = ChartDrawer(
518
527
  chart_data=data,
519
- new_settings_file=self.new_settings_file,
520
528
  theme=cast(Optional[KerykeionChartTheme], self.theme),
521
529
  double_chart_aspect_grid_type=cast(Literal["list", "table"], self.double_chart_aspect_grid_type),
522
530
  chart_language=cast(KerykeionChartLanguage, self.chart_language),
531
+ language_pack=self.language_pack,
523
532
  external_view=external_view,
524
533
  )
525
534
 
@@ -607,31 +616,110 @@ class KerykeionChartSVG:
607
616
  save_aspect_grid_only_svg_file = makeAspectGridOnlySVG
608
617
  makeGridOnlySVG = makeAspectGridOnlySVG
609
618
 
619
+ # ---------------------------------------------------------------------------
620
+ # Legacy NatalAspects wrapper
621
+ # ---------------------------------------------------------------------------
622
+ class NatalAspects:
623
+ """Wrapper replicating the master branch NatalAspects interface.
624
+
625
+ Replacement: AspectsFactory.single_subject_aspects(subject)
626
+ """
627
+
628
+ def __init__(
629
+ self,
630
+ user: Union[AstrologicalSubject, AstrologicalSubjectModel, CompositeSubjectModel],
631
+ new_settings_file: Union[Path, None, dict] = None,
632
+ active_points: Iterable[Union[str, AstrologicalPoint]] = DEFAULT_ACTIVE_POINTS,
633
+ active_aspects: Optional[List[ActiveAspect]] = None,
634
+ *,
635
+ language_pack: Optional[Mapping[str, Any]] = None,
636
+ axis_orb_limit: Optional[float] = None,
637
+ ) -> None:
638
+ _deprecated("NatalAspects", "AspectsFactory.single_chart_aspects")
639
+
640
+ if new_settings_file is not None:
641
+ warnings.warn(
642
+ "'new_settings_file' is deprecated and ignored in Kerykeion v5. Use language_pack instead.",
643
+ DeprecationWarning,
644
+ stacklevel=2,
645
+ )
646
+
647
+ self.user = user.model() if isinstance(user, AstrologicalSubject) else user
648
+ self.new_settings_file = new_settings_file
649
+
650
+ self.language_pack = language_pack
651
+ self.celestial_points: list[Any] = []
652
+ self.aspects_settings: list[Any] = []
653
+ self.axes_orbit_settings = axis_orb_limit
654
+
655
+ self.active_points = list(active_points)
656
+ self._active_points = _normalize_active_points(self.active_points)
657
+ if active_aspects is None:
658
+ active_aspects = list(DEFAULT_ACTIVE_ASPECTS)
659
+ else:
660
+ active_aspects = list(active_aspects)
661
+ self.active_aspects = active_aspects
662
+
663
+ self._aspects_model = None
664
+ self._all_aspects_cache = None
665
+ self._relevant_aspects_cache = None
666
+
667
+ def _build_aspects_model(self):
668
+ if self._aspects_model is None:
669
+ self._aspects_model = AspectsFactory.single_chart_aspects(
670
+ self.user,
671
+ active_points=self._active_points,
672
+ active_aspects=self.active_aspects,
673
+ axis_orb_limit=self.axes_orbit_settings,
674
+ )
675
+ return self._aspects_model
676
+
677
+ @cached_property
678
+ def all_aspects(self):
679
+ if self._all_aspects_cache is None:
680
+ self._all_aspects_cache = list(self._build_aspects_model().all_aspects)
681
+ return self._all_aspects_cache
682
+
683
+ @cached_property
684
+ def relevant_aspects(self):
685
+ if self._relevant_aspects_cache is None:
686
+ self._relevant_aspects_cache = list(self._build_aspects_model().relevant_aspects)
687
+ return self._relevant_aspects_cache
688
+
610
689
  # ---------------------------------------------------------------------------
611
690
  # Legacy SynastryAspects wrapper
612
691
  # ---------------------------------------------------------------------------
613
692
  class SynastryAspects:
614
- """Wrapper replicating the v4 synastry aspects interface."""
693
+ """Wrapper replicating the master branch synastry aspects interface."""
615
694
 
616
695
  def __init__(
617
696
  self,
618
- first: Union[AstrologicalSubject, AstrologicalSubjectModel, CompositeSubjectModel],
619
- second: Union[AstrologicalSubject, AstrologicalSubjectModel, CompositeSubjectModel],
620
- new_settings_file: Union[Path, KerykeionSettingsModel, dict, None] = None,
697
+ kr_object_one: Union[AstrologicalSubject, AstrologicalSubjectModel],
698
+ kr_object_two: Union[AstrologicalSubject, AstrologicalSubjectModel],
699
+ new_settings_file: Union[Path, None, dict] = None,
621
700
  active_points: Iterable[Union[str, AstrologicalPoint]] = DEFAULT_ACTIVE_POINTS,
622
701
  active_aspects: Optional[List[ActiveAspect]] = None,
702
+ *,
703
+ language_pack: Optional[Mapping[str, Any]] = None,
704
+ axis_orb_limit: Optional[float] = None,
623
705
  ) -> None:
624
706
  _deprecated("SynastryAspects", "AspectsFactory.dual_chart_aspects")
625
707
 
626
- self.first_user = first.model() if isinstance(first, AstrologicalSubject) else first
627
- self.second_user = second.model() if isinstance(second, AstrologicalSubject) else second
708
+ if new_settings_file is not None:
709
+ warnings.warn(
710
+ "'new_settings_file' is deprecated and ignored in Kerykeion v5. Use language_pack instead.",
711
+ DeprecationWarning,
712
+ stacklevel=2,
713
+ )
628
714
 
715
+ self.first_user = kr_object_one.model() if isinstance(kr_object_one, AstrologicalSubject) else kr_object_one
716
+ self.second_user = kr_object_two.model() if isinstance(kr_object_two, AstrologicalSubject) else kr_object_two
629
717
  self.new_settings_file = new_settings_file
630
- self.settings = get_settings(new_settings_file)
631
- self.celestial_points = getattr(self.settings, "celestial_points", [])
632
- self.aspects_settings = getattr(self.settings, "aspects", [])
633
- general_settings = getattr(self.settings, "general_settings", None)
634
- self.axes_orbit_settings = getattr(general_settings, "axes_orbit", None)
718
+
719
+ self.language_pack = language_pack
720
+ self.celestial_points: list[Any] = []
721
+ self.aspects_settings: list[Any] = []
722
+ self.axes_orbit_settings = axis_orb_limit
635
723
 
636
724
  self.active_points = list(active_points)
637
725
  self._active_points = _normalize_active_points(self.active_points)
@@ -644,6 +732,8 @@ class SynastryAspects:
644
732
  self._dual_model = None
645
733
  self._all_aspects_cache = None
646
734
  self._relevant_aspects_cache = None
735
+ self._all_aspects: Union[list, None] = None
736
+ self._relevant_aspects: Union[list, None] = None
647
737
 
648
738
  def _build_dual_model(self):
649
739
  if self._dual_model is None:
@@ -652,22 +742,24 @@ class SynastryAspects:
652
742
  self.second_user,
653
743
  active_points=self._active_points,
654
744
  active_aspects=self.active_aspects,
745
+ axis_orb_limit=self.axes_orbit_settings,
655
746
  )
656
747
  return self._dual_model
657
748
 
658
- @property
749
+ @cached_property
659
750
  def all_aspects(self):
660
751
  if self._all_aspects_cache is None:
661
752
  self._all_aspects_cache = list(self._build_dual_model().all_aspects)
662
753
  return self._all_aspects_cache
663
754
 
664
- @property
755
+ @cached_property
665
756
  def relevant_aspects(self):
666
757
  if self._relevant_aspects_cache is None:
667
758
  self._relevant_aspects_cache = list(self._build_dual_model().relevant_aspects)
668
759
  return self._relevant_aspects_cache
669
760
 
670
761
  def get_relevant_aspects(self):
762
+ """Legacy method for compatibility with master branch."""
671
763
  return self.relevant_aspects
672
764
 
673
765
  # ---------------------------------------------------------------------------
@@ -676,5 +768,6 @@ class SynastryAspects:
676
768
  __all__ = [
677
769
  "AstrologicalSubject",
678
770
  "KerykeionChartSVG",
771
+ "NatalAspects",
679
772
  "SynastryAspects",
680
773
  ]