kerykeion 5.0.0a11__py3-none-any.whl → 5.0.0a12__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.

@@ -22,7 +22,7 @@ Classes:
22
22
 
23
23
  Dependencies:
24
24
  - kerykeion.AstrologicalSubjectFactory: For creating astrological subjects
25
- - kerykeion.aspects.SynastryAspectsFactory: For calculating angular relationships
25
+ - kerykeion.aspects.AspectsFactory: For calculating angular relationships
26
26
  - kerykeion.ephemeris_data_factory: For generating time-series planetary positions
27
27
  - kerykeion.kr_types: For type definitions and model structures
28
28
  - datetime: For date/time handling
@@ -59,7 +59,7 @@ from typing import Union, List
59
59
  from datetime import datetime, timedelta
60
60
  from kerykeion.kr_types.kr_models import AstrologicalSubjectModel
61
61
  from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
62
- from kerykeion.aspects import SynastryAspectsFactory
62
+ from kerykeion.aspects import AspectsFactory
63
63
  from kerykeion.ephemeris_data_factory import EphemerisDataFactory
64
64
  from kerykeion.kr_types.kr_literals import AstrologicalPoint
65
65
  from kerykeion.kr_types.kr_models import ActiveAspect, TransitMomentModel, TransitsTimeRangeModel
@@ -227,13 +227,13 @@ class TransitsTimeRangeFactory:
227
227
  See Also:
228
228
  TransitMomentModel: Individual transit moment structure
229
229
  TransitsTimeRangeModel: Complete transit dataset structure
230
- SynastryAspectsFactory: Underlying aspect calculation engine
230
+ AspectsFactory: Underlying aspect calculation engine
231
231
  """
232
232
  transit_moments = []
233
233
 
234
234
  for ephemeris_point in self.ephemeris_data_points:
235
235
  # Calculate aspects between transit positions and natal chart
236
- aspects = SynastryAspectsFactory.from_subjects(
236
+ aspects = AspectsFactory.dual_chart_aspects(
237
237
  ephemeris_point,
238
238
  self.natal_chart,
239
239
  active_points=self.active_points,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kerykeion
3
- Version: 5.0.0a11
3
+ Version: 5.0.0a12
4
4
  Summary: A Python library for astrological calculations, including natal charts, houses, planetary aspects, and SVG chart generation.
5
5
  Project-URL: Homepage, https://www.kerykeion.net/
6
6
  Project-URL: Repository, https://github.com/g-battaglia/kerykeion
@@ -186,10 +186,6 @@ birth_chart_svg = KerykeionChartSVG(john)
186
186
  birth_chart_svg.makeSVG()
187
187
  ```
188
188
 
189
- ```python
190
- birth_chart_svg.makeSVG()
191
- ```
192
-
193
189
  The SVG file will be saved in the home directory.
194
190
  ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20Natal%20Chart.svg)
195
191
 
@@ -221,7 +217,7 @@ synastry_chart.makeSVG()
221
217
  ### Transit Chart
222
218
 
223
219
  ```python
224
- from kerykeion import AstrologicalSubjectFactory
220
+ from kerykeion import AstrologicalSubjectFactory, KerykeionChartSVG
225
221
 
226
222
  transit = AstrologicalSubjectFactory.from_birth_data("Transit", 2025, 6, 8, 8, 45, "Atlanta", "US")
227
223
  subject = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
@@ -315,7 +311,7 @@ You can switch chart language by passing `chart_language` to the `KerykeionChar
315
311
  ```python
316
312
  from kerykeion import AstrologicalSubjectFactory, KerykeionChartSVG
317
313
 
318
- first = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
314
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
319
315
  birth_chart_svg = KerykeionChartSVG(
320
316
  birth_chart,
321
317
  chart_language="IT" # Change to Italian
@@ -342,7 +338,7 @@ To generate a minified SVG, set `minify_svg=True` in the `makeSVG()` method:
342
338
 
343
339
  ```python
344
340
  from kerykeion import AstrologicalSubjectFactory, KerykeionChartSVG
345
- first = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
341
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
346
342
  birth_chart_svg = KerykeionChartSVG(birth_chart)
347
343
  birth_chart_svg.makeSVG(
348
344
  minify=True
@@ -355,7 +351,7 @@ To generate an SVG without CSS variables, set `remove_css_variables=True` in the
355
351
  ```python
356
352
  from kerykeion import AstrologicalSubjectFactory, KerykeionChartSVG
357
353
 
358
- first = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
354
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
359
355
  birth_chart_svg = KerykeionChartSVG(birth_chart)
360
356
  birth_chart_svg.makeSVG(
361
357
  remove_css_variables=True
@@ -366,13 +362,14 @@ This will inline all styles and eliminate CSS variables, resulting in an SVG tha
366
362
 
367
363
  ### Grid Only SVG
368
364
 
369
- It's possible to generate a grid-only SVG, useful for creating a custom layout. To do this, use the `makeGridOnlySVG()` method:
365
+ It's possible to generate a grid-only SVG, useful for creating a custom layout. To do this, use the `makeAspectGridOnlySVG()` method:
370
366
 
371
367
  ```python
372
368
  from kerykeion import AstrologicalSubjectFactory, KerykeionChartSVG
373
- birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon - Aspect Grid Dark Synastry", 1977, 6, 8, 8, 45, "Atlanta", "US")
374
- aspect_grid_dark_synastry_chart = KerykeionChartSVG(aspect_grid_dark_synastry_subject, "Synastry", second, theme="dark")
375
- aspect_grid_dark_synastry_chart.makeAspectGridOnlySVG()
369
+ birth_chart = AstrologicalSubjectFactory.from_birth_data("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
370
+ second = AstrologicalSubjectFactory.from_birth_data("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
371
+ aspect_grid_chart = KerykeionChartSVG(birth_chart, "Synastry", second, theme="dark")
372
+ aspect_grid_chart.makeAspectGridOnlySVG()
376
373
  ```
377
374
  ![John Lennon Birth Chart](https://raw.githubusercontent.com/g-battaglia/kerykeion/refs/heads/master/tests/charts/svg/John%20Lennon%20-%20Aspect%20Grid%20Only%20-%20Natal%20Chart%20-%20Aspect%20Grid%20Only.svg)
378
375
 
@@ -444,17 +441,47 @@ python3 your_script_name.py > file.txt
444
441
 
445
442
  ## Example: Retrieving Aspects
446
443
 
444
+ Kerykeion provides a unified `AspectsFactory` class for calculating astrological aspects within single charts or between two charts:
445
+
447
446
  ```python
448
- from kerykeion import SynastryAspects, AstrologicalSubject
447
+ from kerykeion import AspectsFactory, AstrologicalSubjectFactory
448
+
449
+ # Create astrological subjects
450
+ jack = AstrologicalSubjectFactory.from_birth_data("Jack", 1990, 6, 15, 15, 15, "Roma", "IT")
451
+ jane = AstrologicalSubjectFactory.from_birth_data("Jane", 1991, 10, 25, 21, 0, "Roma", "IT")
452
+
453
+ # For single chart aspects (natal, return, composite, etc.)
454
+ single_chart_aspects = AspectsFactory.single_chart_aspects(jack)
455
+ print(f"Found {len(single_chart_aspects)} aspects in Jack's chart")
456
+ print(single_chart_aspects[0])
457
+ # Output: AspectModel with details like aspect type, orb, planets involved, etc.
458
+
459
+ # For dual chart aspects (synastry, transits, comparisons, etc.)
460
+ dual_chart_aspects = AspectsFactory.dual_chart_aspects(jack, jane)
461
+ print(f"Found {len(dual_chart_aspects)} aspects between Jack and Jane's charts")
462
+ print(dual_chart_aspects[0])
463
+ # Output: AspectModel with cross-chart aspect details
464
+
465
+ # The factory returns structured AspectModel objects with properties like:
466
+ # - p1_name, p2_name: Planet/point names
467
+ # - aspect: Aspect type (conjunction, trine, square, etc.)
468
+ # - orbit: Orb tolerance in degrees
469
+ # - aspect_degrees: Exact degrees for the aspect (0, 60, 90, 120, 180, etc.)
470
+ # - color: Hex color code for visualization
471
+ ```
449
472
 
450
- first = AstrologicalSubjectFactory.from_birth_data("Jack", 1990, 6, 15, 15, 15, "Roma", "IT")
451
- second = AstrologicalSubjectFactory.from_birth_data("Jane", 1991, 10, 25, 21, 0, "Roma", "IT")
473
+ **Advanced Usage with Custom Settings:**
474
+
475
+ ```python
476
+ # You can also customize aspect calculations with custom orb settings
477
+ from kerykeion.settings.config_constants import DEFAULT_ACTIVE_ASPECTS
452
478
 
453
- name = SynastryAspects(first, second)
454
- aspect_list = name.get_relevant_aspects()
455
- print(aspect_list[0])
456
- #> {'p1_name': 'Sun', 'p1_abs_pos': 84.17867971515636, 'p2_name': 'Sun', 'p2_abs_pos': 211.90472999502984, 'aspect': 'trine', 'orbit': 7.726050279873476, 'aspect_degrees': 120, 'color': '#36d100', 'aid': 6, 'diff': 127.72605027987348, 'p1': 0, 'p2': 0}
479
+ # Modify aspect settings if needed
480
+ custom_aspects = DEFAULT_ACTIVE_ASPECTS.copy()
481
+ # ... modify as needed
457
482
 
483
+ # The factory automatically uses the configured settings for orb calculations
484
+ # and filters aspects based on relevance and orb thresholds
458
485
  ```
459
486
 
460
487
  ## Ayanamsa (Sidereal Modes)
@@ -525,7 +552,7 @@ Here's an example of how to set the theme:
525
552
  from kerykeion import AstrologicalSubjectFactory, KerykeionChartSVG
526
553
 
527
554
  dark_theme_subject = AstrologicalSubjectFactory.from_birth_data("John Lennon - Dark Theme", 1940, 10, 9, 18, 30, "Liverpool", "GB")
528
- dark_theme_natal_chart = KerykeionChartSVG(dark_high_contrast_theme_subject, theme="dark_high_contrast")
555
+ dark_theme_natal_chart = KerykeionChartSVG(dark_theme_subject, theme="dark_high_contrast")
529
556
  dark_theme_natal_chart.makeSVG()
530
557
  ```
531
558
 
@@ -617,7 +644,7 @@ Clone the repository or download the ZIP via the GitHub interface.
617
644
 
618
645
  ## Integrating Kerykeion into Your Project
619
646
 
620
- If you would like to incorporate Kerykeions astrological features into your application, please reach out via [email](mailto:kerykeion.astrology@gmail.com?subject=Integration%20Request). Whether you need custom features, support, or specialized consulting, I am happy to discuss potential collaborations.
647
+ If you would like to incorporate Kerykeion's astrological features into your application, please reach out via [email](mailto:kerykeion.astrology@gmail.com?subject=Integration%20Request). Whether you need custom features, support, or specialized consulting, I am happy to discuss potential collaborations.
621
648
 
622
649
  ## License
623
650
 
@@ -1,21 +1,20 @@
1
- kerykeion/__init__.py,sha256=0nw7gz0b1fGUvRlNfIMOGognUd9y6cP1hXxHN2LQ_nM,1338
2
- kerykeion/astrological_subject_factory.py,sha256=xyWbrThNuUnjKVrglJKCNdiKlnDmJU8GiRRu8QlIlL8,83659
1
+ kerykeion/__init__.py,sha256=WTTZBOe40IuvcINRRrsqinEkTFzaJNbPcZ8iO6F3fvw,1274
2
+ kerykeion/astrological_subject_factory.py,sha256=TrnZ_jIphKzu7NqxlL5vp5JELzuPgxIz1KtrW7W2-5M,83655
3
3
  kerykeion/composite_subject_factory.py,sha256=sqs7CiP_3lGI9-FeRFMFL7PIXTlSUaXA9pUDI_5zPZw,17124
4
4
  kerykeion/ephemeris_data_factory.py,sha256=Iwd8KkBB-WmI8AEwrhe9ze8dicA5kvpflT_yQD9XkAY,20111
5
5
  kerykeion/fetch_geonames.py,sha256=SPI4fSvD59C-IVpaoeOHuD7_kjGbTLo2fypO2x57-p4,5432
6
6
  kerykeion/planetary_return_factory.py,sha256=7fwfjhJATFmUNJkIqgaz07sWtpwHPjHvF2oFyPGfga4,37246
7
- kerykeion/relationship_score_factory.py,sha256=aYpWkkcZGNpmCW8Ul5FcXh3skVFSN07WPZroL1KXDoc,11135
7
+ kerykeion/relationship_score_factory.py,sha256=kcr0qEA4_2oQ_2g8IcrHgpVEyb9uAm4EmVWJAGsoCtg,11099
8
8
  kerykeion/report.py,sha256=dUtI70wUjOouqNE1pf0ZYFY4qme9pR7WQRbs_ExEkjM,3029
9
- kerykeion/transits_time_range_factory.py,sha256=n25xQeqiKGYGhBvxUJKT6Dxc7L7lw46TGBy3L8RSb_g,13419
9
+ kerykeion/transits_time_range_factory.py,sha256=xFEdOqYINTBluwp-CKeYTJgANlPEeVw4TYMLigiC30M,13392
10
10
  kerykeion/utilities.py,sha256=MtVyZ2dbHrJPuDoPKPrkx0MrB83fxcbGtPx87piHCtQ,23471
11
- kerykeion/aspects/__init__.py,sha256=i1hg04VL15s-LVGOHuTWJsicv_HNwT3b2v6_-16s6A4,394
11
+ kerykeion/aspects/__init__.py,sha256=csJmxvLdBu-bHuW676f3dpY__Qyc6LwRyrpWVTh3n1A,287
12
+ kerykeion/aspects/aspects_factory.py,sha256=09Hm50c5J-OiMwgsoxZXWidCBgZc2gzhwz95MdHJUy4,22664
12
13
  kerykeion/aspects/aspects_utils.py,sha256=mOj2AqVGnY2vsGsezPfxI_crPJsN54p8qjpmCk5iupM,3093
13
- kerykeion/aspects/natal_aspects_factory.py,sha256=If-XV1_QLpQPKjka_dJjMOqhAyAIi7icwxhhOEhwzm4,9318
14
- kerykeion/aspects/synastry_aspects_factory.py,sha256=NpOn-h6nqKbkVpDucn8i-3lW_tqNZyUOQGNXCJ36ULU,12690
15
14
  kerykeion/charts/__init__.py,sha256=i9NMZ7LdkllPlqQSi1or9gTobHbROGDKmJhBDO4R0mA,128
16
15
  kerykeion/charts/charts_utils.py,sha256=_z-lA7ibIQ5vhr1NxpzJFyPmMp-Sh1iyYxuO56DDO4w,62922
17
16
  kerykeion/charts/draw_planets.py,sha256=6S0sCAktZJa7eckb-h1voYbe0H27vL9otcJzA0dqFH0,28167
18
- kerykeion/charts/kerykeion_chart_svg.py,sha256=ILsSV8QDEgtraYIn60ZQVOYeNptX5IarbzZwwEitVc4,97414
17
+ kerykeion/charts/kerykeion_chart_svg.py,sha256=pNSmGZYtFGSx17EKcdSSYunP_oKy3xLSiq_CmbGz8Fs,97285
19
18
  kerykeion/charts/templates/aspect_grid_only.xml,sha256=lBHBj5bS5klGnv7QMuFxQjhlE6VZRaOgW93akLgRjX4,70055
20
19
  kerykeion/charts/templates/chart.xml,sha256=r3a_csMqcoqeOnDA3YCD-iUxdqgRw5GV1GOf1Cp0e_E,79940
21
20
  kerykeion/charts/templates/wheel_only.xml,sha256=X2-bwmEvQnZcM5Om7JXIWZSoSmFLAm4sY31heSq5u1k,71388
@@ -25,14 +24,14 @@ kerykeion/charts/themes/dark.css,sha256=XVspznDRNMXsFzk7hY7IB7AI58alPAV_-CgV3gCK
25
24
  kerykeion/charts/themes/light.css,sha256=5eyUzhVlRjG6lPHKnprLum0HuRtPIJhMBzpGfzoTjnQ,7590
26
25
  kerykeion/charts/themes/strawberry.css,sha256=UtcfRsCT-M9OZs_SoclWGZ0jDJiWvQjHTeI4M1jf7pQ,8314
27
26
  kerykeion/house_comparison/__init__.py,sha256=6FYHyQY3nUJifZ2kEVCHB8cN3TjFA1q2yhmeRwJlias,238
28
- kerykeion/house_comparison/house_comparison_factory.py,sha256=Vn4_Hviy20_nsSf_vjEKZ9h-QsJDFtapM1Wydvwgx4w,3345
29
- kerykeion/house_comparison/house_comparison_models.py,sha256=R9EW5F3fiIKIm8qrwTxtXhNOGDpf1-Lh9hbM1uK83oE,1549
30
- kerykeion/house_comparison/house_comparison_utils.py,sha256=Q5pdP7hmUEB3cqE7QkOYNu_laQ1Nj83Fmn_F8YJkKik,3773
27
+ kerykeion/house_comparison/house_comparison_factory.py,sha256=0C48isz_yb6Pz9EQoQjEzmmhqY-3fh4MGW7sTnW-IUA,4613
28
+ kerykeion/house_comparison/house_comparison_models.py,sha256=RPzJeCFiq0GioWI6IONJEUqsK9I_Dksp5mOHNY-j1PI,2865
29
+ kerykeion/house_comparison/house_comparison_utils.py,sha256=JzWAAtBbKO1bDBRMh-D8hWROyvFo4z2pfmc6NMIN2RU,5167
31
30
  kerykeion/kr_types/__init__.py,sha256=dePcQY5rrgtUENhqnjcVx6j7iQJPo_1rmD0bLeIO3HA,1384
32
31
  kerykeion/kr_types/chart_types.py,sha256=ofMYk7NRalSsdQcLVkpCbOb-dhdjYHEqIb_WPLtD0rM,2429
33
32
  kerykeion/kr_types/kerykeion_exception.py,sha256=vTYdwj_mL-Q-MqHJvEzzBXxQ5YI2kAwUC6ImoWxMKXc,454
34
33
  kerykeion/kr_types/kr_literals.py,sha256=4kJhzm_0LERiJEJks0KgDyThueMZj_F1OK2Far5SMZc,4870
35
- kerykeion/kr_types/kr_models.py,sha256=cwpmP5CMM8Bi8aYfST6tVivFe3VuZh9S4jLoDWBAWM8,13601
34
+ kerykeion/kr_types/kr_models.py,sha256=5wG3bh7EvCD0FTYe-W2e8jNLK408f3JQQhda6DVrOnw,14180
36
35
  kerykeion/kr_types/settings_models.py,sha256=Llosnvw-6NHJMbdKltPHQDLR-Ltn7ZpWkjEbLJ2C6AY,17488
37
36
  kerykeion/settings/__init__.py,sha256=NYCwcvEfn9qJ498fv1H_Gix8e-crJ3CruV13A-e2CnI,134
38
37
  kerykeion/settings/config_constants.py,sha256=hxDZnFKWFhGrYMejDISbYT-phUk1Qqfvt-4wBG79rGA,2233
@@ -44,7 +43,8 @@ kerykeion/settings/legacy/legacy_chart_aspects_settings.py,sha256=tO4tgPgPP07_wu
44
43
  kerykeion/settings/legacy/legacy_color_settings.py,sha256=gBUmGSNvvLzRYbdVtzwTDnMwWoh4tOCyT_9Q6aQRv_s,2620
45
44
  kerykeion/sweph/README.md,sha256=L7FtNAJTWtrZNGKa8MX87SjduFYPYxwWhaI5fmtzNZo,73
46
45
  kerykeion/sweph/seas_18.se1,sha256=X9nCqhZU43wJpq61WAdueVQJt9xL2UjrwPqn1Kdoa1s,223002
47
- kerykeion-5.0.0a11.dist-info/METADATA,sha256=bIW3d40hSJyDoA0KIacZoCko2_kd6TjNGvZ_DG82vPU,25544
48
- kerykeion-5.0.0a11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
- kerykeion-5.0.0a11.dist-info/licenses/LICENSE,sha256=UTLH8EdbAsgQei4PA2PnBCPGLSZkq5J-dhkyJuXgWQU,34273
50
- kerykeion-5.0.0a11.dist-info/RECORD,,
46
+ kerykeion/sweph/sefstars.txt,sha256=GLDcr75bckB3PauiwDijJfWz_EFj9h4Kf06Sq9T1F8Y,136618
47
+ kerykeion-5.0.0a12.dist-info/METADATA,sha256=uglXk2FOHWcHfjDYwJBPu-32jDEVQiC_OxRb4TP7tQE,26756
48
+ kerykeion-5.0.0a12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
+ kerykeion-5.0.0a12.dist-info/licenses/LICENSE,sha256=UTLH8EdbAsgQei4PA2PnBCPGLSZkq5J-dhkyJuXgWQU,34273
50
+ kerykeion-5.0.0a12.dist-info/RECORD,,
@@ -1,235 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- This is part of Kerykeion (C) 2025 Giacomo Battaglia
4
- """
5
-
6
- import logging
7
- from typing import Union, List, Optional
8
-
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.kr_types.kr_models import AstrologicalSubjectModel, AspectModel, ActiveAspect, CompositeSubjectModel, PlanetReturnModel, NatalAspectsModel
12
- from kerykeion.kr_types.kr_literals import AstrologicalPoint
13
- from kerykeion.settings.config_constants import DEFAULT_ACTIVE_ASPECTS, DEFAULT_AXIS_ORBIT
14
- from kerykeion.settings.legacy.legacy_celestial_points_settings import DEFAULT_CELESTIAL_POINTS_SETTINGS
15
- from kerykeion.settings.legacy.legacy_chart_aspects_settings import DEFAULT_CHART_ASPECTS_SETTINGS
16
- from kerykeion.utilities import find_common_active_points
17
-
18
- # Axes constants for orb filtering
19
- AXES_LIST = [
20
- "Ascendant",
21
- "Medium_Coeli",
22
- "Descendant",
23
- "Imum_Coeli",
24
- ]
25
-
26
-
27
- class NatalAspectsFactory:
28
- """
29
- Factory class for creating natal aspects analysis.
30
-
31
- This factory calculates all aspects in a birth chart and provides both
32
- comprehensive and filtered aspect lists based on orb settings and relevance.
33
- """
34
-
35
- @staticmethod
36
- def from_subject(
37
- user: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
38
- *,
39
- active_points: Optional[List[AstrologicalPoint]] = None,
40
- active_aspects: Optional[List[ActiveAspect]] = None,
41
- ) -> NatalAspectsModel:
42
- """
43
- Create natal aspects analysis from an existing astrological subject.
44
-
45
- Args:
46
- user: The astrological subject for aspect calculation
47
-
48
- Kwargs:
49
- active_points: List of points to include in calculations
50
- active_aspects: List of aspects with their orb settings
51
-
52
- Returns:
53
- NatalAspectsModel containing all calculated aspects data
54
- """
55
- # Initialize settings and configurations
56
- celestial_points = DEFAULT_CELESTIAL_POINTS_SETTINGS
57
- aspects_settings = DEFAULT_CHART_ASPECTS_SETTINGS
58
- axes_orbit_settings = DEFAULT_AXIS_ORBIT
59
-
60
- # Set active aspects with default fallback
61
- active_aspects_resolved = active_aspects if active_aspects is not None else DEFAULT_ACTIVE_ASPECTS
62
-
63
- # Determine active points to use
64
- if active_points is None:
65
- active_points_resolved = user.active_points
66
- else:
67
- active_points_resolved = find_common_active_points(
68
- user.active_points,
69
- active_points,
70
- )
71
-
72
- return NatalAspectsFactory._create_natal_aspects_model(
73
- user, active_points_resolved, active_aspects_resolved,
74
- aspects_settings, axes_orbit_settings, celestial_points
75
- )
76
-
77
- @staticmethod
78
- def _create_natal_aspects_model(
79
- user: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
80
- active_points_resolved: List[AstrologicalPoint],
81
- active_aspects_resolved: List[ActiveAspect],
82
- aspects_settings: List[dict],
83
- axes_orbit_settings: float,
84
- celestial_points: List[dict]
85
- ) -> NatalAspectsModel:
86
- """
87
- Create the complete natal aspects model with all calculations.
88
-
89
- Returns:
90
- NatalAspectsModel containing all aspects data
91
- """
92
- all_aspects = NatalAspectsFactory._calculate_all_aspects(
93
- user, active_points_resolved, active_aspects_resolved, aspects_settings, celestial_points
94
- )
95
- relevant_aspects = NatalAspectsFactory._filter_relevant_aspects(all_aspects, axes_orbit_settings)
96
-
97
- return NatalAspectsModel(
98
- subject=user,
99
- all_aspects=all_aspects,
100
- relevant_aspects=relevant_aspects,
101
- active_points=active_points_resolved,
102
- active_aspects=active_aspects_resolved,
103
- )
104
-
105
- @staticmethod
106
- def _calculate_all_aspects(
107
- user: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel],
108
- active_points: List[AstrologicalPoint],
109
- active_aspects: List[ActiveAspect],
110
- aspects_settings: List[dict],
111
- celestial_points: List[dict]
112
- ) -> List[AspectModel]:
113
- """
114
- Calculate all aspects between active points in the natal chart.
115
-
116
- This method handles all aspect calculations including settings updates,
117
- opposite pair filtering, and planet ID resolution in a single comprehensive method.
118
-
119
- Returns:
120
- List of all calculated AspectModel instances
121
- """
122
- active_points_list = get_active_points_list(user, active_points)
123
-
124
- # Update aspects settings with active aspects orbs
125
- filtered_settings = []
126
- for aspect_setting in aspects_settings:
127
- for active_aspect in active_aspects:
128
- if aspect_setting["name"] == active_aspect["name"]:
129
- aspect_setting = aspect_setting.copy() # Don't modify original
130
- aspect_setting["orb"] = active_aspect["orb"]
131
- filtered_settings.append(aspect_setting)
132
- break
133
-
134
- # Define opposite pairs that should be skipped
135
- opposite_pairs = {
136
- ("Ascendant", "Descendant"),
137
- ("Descendant", "Ascendant"),
138
- ("Medium_Coeli", "Imum_Coeli"),
139
- ("Imum_Coeli", "Medium_Coeli"),
140
- ("True_Node", "True_South_Node"),
141
- ("Mean_Node", "Mean_South_Node"),
142
- ("True_South_Node", "True_Node"),
143
- ("Mean_South_Node", "Mean_Node"),
144
- }
145
-
146
- all_aspects_list = []
147
-
148
- for first in range(len(active_points_list)):
149
- # Generate aspects list without repetitions
150
- for second in range(first + 1, len(active_points_list)):
151
- # Skip predefined opposite pairs (AC/DC, MC/IC, North/South nodes)
152
- first_name = active_points_list[first]["name"]
153
- second_name = active_points_list[second]["name"]
154
-
155
- if (first_name, second_name) in opposite_pairs:
156
- continue
157
-
158
- aspect = get_aspect_from_two_points(
159
- filtered_settings,
160
- active_points_list[first]["abs_pos"],
161
- active_points_list[second]["abs_pos"]
162
- )
163
-
164
- if aspect["verdict"]:
165
- # Get planet IDs directly from celestial points settings
166
- first_planet_id = 0
167
- second_planet_id = 0
168
-
169
- for planet in celestial_points:
170
- if planet["name"] == first_name:
171
- first_planet_id = planet["id"]
172
- if planet["name"] == second_name:
173
- second_planet_id = planet["id"]
174
-
175
- aspect_model = AspectModel(
176
- p1_name=first_name,
177
- p1_owner=user.name,
178
- p1_abs_pos=active_points_list[first]["abs_pos"],
179
- p2_name=second_name,
180
- p2_owner=user.name,
181
- p2_abs_pos=active_points_list[second]["abs_pos"],
182
- aspect=aspect["name"],
183
- orbit=aspect["orbit"],
184
- aspect_degrees=aspect["aspect_degrees"],
185
- diff=aspect["diff"],
186
- p1=first_planet_id,
187
- p2=second_planet_id,
188
- )
189
- all_aspects_list.append(aspect_model)
190
-
191
- return all_aspects_list
192
-
193
- @staticmethod
194
- def _filter_relevant_aspects(all_aspects: List[AspectModel], axes_orbit_settings: float) -> List[AspectModel]:
195
- """
196
- Filter aspects based on orb thresholds for axes and other comprehensive criteria.
197
-
198
- This method consolidates all filtering logic including axes checks and orb thresholds
199
- into a single comprehensive filtering method.
200
-
201
- Args:
202
- all_aspects: Complete list of calculated aspects
203
- axes_orbit_settings: Orb threshold for axes aspects
204
-
205
- Returns:
206
- Filtered list of relevant aspects
207
- """
208
- logging.debug("Calculating relevant aspects by filtering orbs...")
209
-
210
- relevant_aspects = []
211
-
212
- for aspect in all_aspects:
213
- # Check if aspect involves any of the chart axes and apply stricter orb limits
214
- aspect_involves_axes = (aspect.p1_name in AXES_LIST or aspect.p2_name in AXES_LIST)
215
-
216
- if aspect_involves_axes and abs(aspect.orbit) >= axes_orbit_settings:
217
- continue
218
-
219
- relevant_aspects.append(aspect)
220
-
221
- return relevant_aspects
222
-
223
-
224
- if __name__ == "__main__":
225
- from kerykeion.utilities import setup_logging
226
-
227
- setup_logging(level="debug")
228
-
229
- # Create subject using AstrologicalSubjectFactory
230
- johnny = AstrologicalSubjectFactory.from_birth_data("Johnny Depp", 1963, 6, 9, 0, 0, city="Owensboro", nation="US")
231
-
232
- # Create aspects analysis from subject
233
- natal_aspects = NatalAspectsFactory.from_subject(johnny)
234
- print(f"All aspects count: {len(natal_aspects.all_aspects)}")
235
- print(f"Relevant aspects count: {len(natal_aspects.relevant_aspects)}")