kerykeion 5.0.0a10__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.

Files changed (33) hide show
  1. kerykeion/__init__.py +4 -9
  2. kerykeion/aspects/__init__.py +2 -4
  3. kerykeion/aspects/aspects_factory.py +514 -0
  4. kerykeion/astrological_subject_factory.py +685 -79
  5. kerykeion/charts/draw_planets.py +584 -343
  6. kerykeion/charts/kerykeion_chart_svg.py +10 -16
  7. kerykeion/charts/templates/wheel_only.xml +1 -1
  8. kerykeion/composite_subject_factory.py +228 -9
  9. kerykeion/ephemeris_data_factory.py +431 -0
  10. kerykeion/fetch_geonames.py +27 -8
  11. kerykeion/house_comparison/house_comparison_factory.py +48 -15
  12. kerykeion/house_comparison/house_comparison_models.py +51 -13
  13. kerykeion/house_comparison/house_comparison_utils.py +35 -5
  14. kerykeion/kr_types/kerykeion_exception.py +6 -0
  15. kerykeion/kr_types/kr_models.py +82 -12
  16. kerykeion/planetary_return_factory.py +532 -32
  17. kerykeion/relationship_score_factory.py +98 -44
  18. kerykeion/report.py +7 -0
  19. kerykeion/sweph/sefstars.txt +1602 -0
  20. kerykeion/transits_time_range_factory.py +293 -0
  21. kerykeion/utilities.py +129 -67
  22. {kerykeion-5.0.0a10.dist-info → kerykeion-5.0.0a12.dist-info}/METADATA +49 -22
  23. kerykeion-5.0.0a12.dist-info/RECORD +50 -0
  24. kerykeion/aspects/natal_aspects_factory.py +0 -236
  25. kerykeion/aspects/synastry_aspects_factory.py +0 -234
  26. kerykeion/charts/draw_planets_v2.py +0 -648
  27. kerykeion/charts/draw_planets_v3.py +0 -679
  28. kerykeion/enums.py +0 -57
  29. kerykeion/ephemeris_data.py +0 -238
  30. kerykeion/transits_time_range.py +0 -128
  31. kerykeion-5.0.0a10.dist-info/RECORD +0 -53
  32. {kerykeion-5.0.0a10.dist-info → kerykeion-5.0.0a12.dist-info}/WHEEL +0 -0
  33. {kerykeion-5.0.0a10.dist-info → kerykeion-5.0.0a12.dist-info}/licenses/LICENSE +0 -0
kerykeion/utilities.py CHANGED
@@ -1,3 +1,9 @@
1
+ """
2
+ Author: Giacomo Battaglia
3
+ Copyright: (C) 2025 Kerykeion Project
4
+ License: AGPL-3.0
5
+ """
6
+
1
7
  from kerykeion.kr_types import (
2
8
  KerykeionPointModel,
3
9
  KerykeionException,
@@ -19,7 +25,18 @@ if TYPE_CHECKING:
19
25
 
20
26
 
21
27
  def get_number_from_name(name: AstrologicalPoint) -> int:
22
- """Utility function, gets planet id from the name."""
28
+ """
29
+ Convert an astrological point name to its corresponding numerical identifier.
30
+
31
+ Args:
32
+ name: The name of the astrological point
33
+
34
+ Returns:
35
+ The numerical identifier used in Swiss Ephemeris calculations
36
+
37
+ Raises:
38
+ KerykeionException: If the name is not recognized
39
+ """
23
40
 
24
41
  if name == "Sun":
25
42
  return 0
@@ -70,18 +87,18 @@ def get_kerykeion_point_from_degree(
70
87
  degree: Union[int, float], name: Union[AstrologicalPoint, Houses], point_type: PointType
71
88
  ) -> KerykeionPointModel:
72
89
  """
73
- Returns a KerykeionPointModel object based on the given degree.
90
+ Create a KerykeionPointModel from a degree position.
74
91
 
75
92
  Args:
76
- degree (Union[int, float]): The degree of the celestial point.
77
- name (str): The name of the celestial point.
78
- point_type (PointType): The type of the celestial point.
79
-
80
- Raises:
81
- KerykeionException: If the degree is not within the valid range (0-360).
93
+ degree: The degree position (0-360, negative values are converted to positive)
94
+ name: The name of the celestial point or house
95
+ point_type: The type classification of the point
82
96
 
83
97
  Returns:
84
- KerykeionPointModel: The model representing the celestial point.
98
+ A KerykeionPointModel with calculated zodiac sign, position, and properties
99
+
100
+ Raises:
101
+ KerykeionException: If the degree is >= 360 after normalization
85
102
  """
86
103
  # If - single degree is given, convert it to a positive degree
87
104
  if degree < 0:
@@ -124,10 +141,10 @@ def get_kerykeion_point_from_degree(
124
141
 
125
142
  def setup_logging(level: str) -> None:
126
143
  """
127
- Setup logging for testing.
144
+ Configure logging for the application.
128
145
 
129
146
  Args:
130
- level: Log level as a string, options: debug, info, warning, error
147
+ level: Log level as string (debug, info, warning, error, critical)
131
148
  """
132
149
  logging_options: dict[str, int] = {
133
150
  "debug": logging.DEBUG,
@@ -145,18 +162,23 @@ def is_point_between(
145
162
  start_point: Union[int, float], end_point: Union[int, float], evaluated_point: Union[int, float]
146
163
  ) -> bool:
147
164
  """
148
- Determines if a point is between two others on a circle, with additional rules:
149
- - If evaluated_point == start_point, it is considered between.
150
- - If evaluated_point == end_point, it is NOT considered between.
151
- - The range between start_point and end_point must not exceed 180°.
165
+ Determine if a point lies between two other points on a circle.
166
+
167
+ Special rules:
168
+ - If evaluated_point equals start_point, returns True
169
+ - If evaluated_point equals end_point, returns False
170
+ - The arc between start_point and end_point must not exceed 180°
152
171
 
153
172
  Args:
154
- - start_point: The first point on the circle.
155
- - end_point: The second point on the circle.
156
- - evaluated_point: The point to check.
173
+ start_point: The starting point on the circle
174
+ end_point: The ending point on the circle
175
+ evaluated_point: The point to evaluate
157
176
 
158
177
  Returns:
159
- - True if evaluated_point is between start_point and end_point, False otherwise.
178
+ True if evaluated_point is between start_point and end_point, False otherwise
179
+
180
+ Raises:
181
+ KerykeionException: If the angular difference exceeds 180°
160
182
  """
161
183
 
162
184
  # Normalize angles to [0, 360)
@@ -193,17 +215,17 @@ def is_point_between(
193
215
 
194
216
  def get_planet_house(planet_position_degree: Union[int, float], houses_degree_ut_list: list) -> Houses:
195
217
  """
196
- Determines the house in which a planet is located based on its position in degrees.
218
+ Determine which house contains a planet based on its degree position.
197
219
 
198
220
  Args:
199
- planet_position_degree (Union[int, float]): The position of the planet in degrees.
200
- houses_degree_ut_list (list): A list of the houses in degrees (0-360).
221
+ planet_position_degree: The planet's position in degrees (0-360)
222
+ houses_degree_ut_list: List of house cusp degrees
201
223
 
202
224
  Returns:
203
- str: The house in which the planet is located.
225
+ The house name containing the planet
204
226
 
205
227
  Raises:
206
- ValueError: If the planet's position does not fall within any house range.
228
+ ValueError: If the planet's position doesn't fall within any house range
207
229
  """
208
230
 
209
231
  house_names = get_args(Houses)
@@ -222,13 +244,16 @@ def get_planet_house(planet_position_degree: Union[int, float], houses_degree_ut
222
244
 
223
245
  def get_moon_emoji_from_phase_int(phase: int) -> LunarPhaseEmoji:
224
246
  """
225
- Returns the emoji of the moon phase.
247
+ Get the emoji representation of a lunar phase.
226
248
 
227
249
  Args:
228
- - phase: The phase of the moon (0-28)
250
+ phase: The lunar phase number (0-28)
229
251
 
230
252
  Returns:
231
- - The emoji of the moon phase
253
+ The corresponding emoji for the lunar phase
254
+
255
+ Raises:
256
+ KerykeionException: If phase is outside valid range
232
257
  """
233
258
 
234
259
  lunar_phase_emojis = get_args(LunarPhaseEmoji)
@@ -258,13 +283,16 @@ def get_moon_emoji_from_phase_int(phase: int) -> LunarPhaseEmoji:
258
283
 
259
284
  def get_moon_phase_name_from_phase_int(phase: int) -> LunarPhaseName:
260
285
  """
261
- Returns the name of the moon phase.
286
+ Get the name of a lunar phase from its numerical value.
262
287
 
263
288
  Args:
264
- - phase: The phase of the moon (0-28)
289
+ phase: The lunar phase number (0-28)
265
290
 
266
291
  Returns:
267
- - The name of the moon phase
292
+ The corresponding name for the lunar phase
293
+
294
+ Raises:
295
+ KerykeionException: If phase is outside valid range
268
296
  """
269
297
  lunar_phase_names = get_args(LunarPhaseName)
270
298
 
@@ -293,8 +321,15 @@ def get_moon_phase_name_from_phase_int(phase: int) -> LunarPhaseName:
293
321
 
294
322
  def check_and_adjust_polar_latitude(latitude: float) -> float:
295
323
  """
296
- Utility function to check if the location is in the polar circle.
297
- If it is, it sets the latitude to 66 or -66 degrees.
324
+ Adjust latitude values for polar regions to prevent calculation errors.
325
+
326
+ Latitudes beyond ±66° are clamped to ±66° for house calculations.
327
+
328
+ Args:
329
+ latitude: The original latitude value
330
+
331
+ Returns:
332
+ The adjusted latitude value, clamped between -66° and 66°
298
333
  """
299
334
  if latitude > 66.0:
300
335
  latitude = 66.0
@@ -311,7 +346,13 @@ def get_houses_list(
311
346
  subject: Union[AstrologicalSubjectModel, CompositeSubjectModel, PlanetReturnModel]
312
347
  ) -> list[KerykeionPointModel]:
313
348
  """
314
- Return the names of the houses in the order of the houses.
349
+ Get a list of house objects in order from the subject.
350
+
351
+ Args:
352
+ subject: The astrological subject containing house data
353
+
354
+ Returns:
355
+ List of KerykeionPointModel objects representing the houses
315
356
  """
316
357
  houses_absolute_position_list = []
317
358
  for house in subject.houses_names_list:
@@ -324,8 +365,13 @@ def get_available_astrological_points_list(
324
365
  subject: AstrologicalSubjectModel
325
366
  ) -> list[KerykeionPointModel]:
326
367
  """
327
- Return the names of the planets in the order of the planets.
328
- The names can be used to access the planets from the AstrologicalSubject object with the __getitem__ method or the [] operator.
368
+ Get a list of active astrological point objects from the subject.
369
+
370
+ Args:
371
+ subject: The astrological subject containing point data
372
+
373
+ Returns:
374
+ List of KerykeionPointModel objects for all active points
329
375
  """
330
376
  planets_absolute_position_list = []
331
377
  for planet in subject.active_points:
@@ -336,17 +382,17 @@ def get_available_astrological_points_list(
336
382
 
337
383
  def circular_mean(first_position: Union[int, float], second_position: Union[int, float]) -> float:
338
384
  """
339
- Computes the circular mean of two astrological positions (e.g., house cusps, planets).
385
+ Calculate the circular mean of two angular positions.
340
386
 
341
- This function ensures that positions crossing Aries (360°) are correctly averaged,
342
- avoiding errors that occur with simple linear means.
387
+ This method correctly handles positions that cross the 0°/360° boundary,
388
+ avoiding errors that occur with simple arithmetic means.
343
389
 
344
390
  Args:
345
- position1 (Union[int, float]): First position in degrees (0-360).
346
- position2 (Union[int, float]): Second position in degrees (0-360).
391
+ first_position: First angular position in degrees (0-360)
392
+ second_position: Second angular position in degrees (0-360)
347
393
 
348
394
  Returns:
349
- float: The circular mean position in degrees (0-360).
395
+ The circular mean position in degrees (0-360)
350
396
  """
351
397
  x = (math.cos(math.radians(first_position)) + math.cos(math.radians(second_position))) / 2
352
398
  y = (math.sin(math.radians(first_position)) + math.sin(math.radians(second_position))) / 2
@@ -361,14 +407,14 @@ def circular_mean(first_position: Union[int, float], second_position: Union[int,
361
407
 
362
408
  def calculate_moon_phase(moon_abs_pos: float, sun_abs_pos: float) -> LunarPhaseModel:
363
409
  """
364
- Calculate the lunar phase based on the positions of the moon and sun.
410
+ Calculate lunar phase information from Sun and Moon positions.
365
411
 
366
412
  Args:
367
- - moon_abs_pos (float): The absolute position of the moon.
368
- - sun_abs_pos (float): The absolute position of the sun.
413
+ moon_abs_pos: Absolute position of the Moon in degrees
414
+ sun_abs_pos: Absolute position of the Sun in degrees
369
415
 
370
416
  Returns:
371
- - dict: A dictionary containing the lunar phase information.
417
+ LunarPhaseModel containing phase data, emoji, and name
372
418
  """
373
419
  # Initialize moon_phase and sun_phase to None in case of an error
374
420
  moon_phase, sun_phase = None, None
@@ -408,14 +454,13 @@ def calculate_moon_phase(moon_abs_pos: float, sun_abs_pos: float) -> LunarPhaseM
408
454
 
409
455
  def circular_sort(degrees: list[Union[int, float]]) -> list[Union[int, float]]:
410
456
  """
411
- Sort a list of degrees in a circular manner, starting from the first element
412
- and progressing clockwise around the circle.
457
+ Sort degrees in circular clockwise progression starting from the first element.
413
458
 
414
459
  Args:
415
- degrees: A list of numeric values representing degrees
460
+ degrees: List of numeric degree values
416
461
 
417
462
  Returns:
418
- A list sorted based on circular clockwise progression from the first element
463
+ List sorted by clockwise distance from the first element
419
464
 
420
465
  Raises:
421
466
  ValueError: If the list is empty or contains non-numeric values
@@ -458,14 +503,16 @@ def circular_sort(degrees: list[Union[int, float]]) -> list[Union[int, float]]:
458
503
 
459
504
  def inline_css_variables_in_svg(svg_content: str) -> str:
460
505
  """
461
- Process an SVG string to inline all CSS custom properties.
506
+ Replace CSS custom properties (variables) with their values in SVG content.
507
+
508
+ Extracts CSS variables from style blocks, replaces var() references with actual values,
509
+ and removes all style blocks from the SVG.
462
510
 
463
511
  Args:
464
- svg_content (str): The original SVG string with CSS variables
512
+ svg_content: The original SVG string with CSS variables
465
513
 
466
514
  Returns:
467
- str: The modified SVG with all CSS variables replaced by their values
468
- and all style blocks removed
515
+ Modified SVG with CSS variables inlined and style blocks removed
469
516
  """
470
517
  # Find and extract CSS custom properties from style tags
471
518
  css_variable_map = {}
@@ -486,6 +533,15 @@ def inline_css_variables_in_svg(svg_content: str) -> str:
486
533
 
487
534
  # Function to replace var() references with their actual values
488
535
  def replace_css_variable_reference(match):
536
+ """
537
+ Replace CSS variable references with their actual values.
538
+
539
+ Args:
540
+ match: Regular expression match object containing variable name and optional fallback.
541
+
542
+ Returns:
543
+ str: The resolved CSS variable value or fallback value.
544
+ """
489
545
  variable_name = match.group(1).strip()
490
546
  fallback_value = match.group(2) if match.group(2) else None
491
547
 
@@ -510,13 +566,13 @@ def inline_css_variables_in_svg(svg_content: str) -> str:
510
566
 
511
567
  def datetime_to_julian(dt: datetime) -> float:
512
568
  """
513
- Converts a Python datetime object to Julian day.
569
+ Convert a Python datetime object to Julian Day Number.
514
570
 
515
571
  Args:
516
- dt: A datetime object
572
+ dt: The datetime object to convert
517
573
 
518
574
  Returns:
519
- float: The corresponding Julian day (JD)
575
+ The corresponding Julian Day Number (JD) as a float
520
576
  """
521
577
  # Extract year, month and day
522
578
  year = dt.year
@@ -548,13 +604,13 @@ def datetime_to_julian(dt: datetime) -> float:
548
604
 
549
605
  def julian_to_datetime(jd):
550
606
  """
551
- Converts a Julian day to a Python datetime object.
607
+ Convert a Julian Day Number to a Python datetime object.
552
608
 
553
609
  Args:
554
- jd: Julian day number (float)
610
+ jd: Julian Day Number as a float
555
611
 
556
612
  Returns:
557
- datetime: The corresponding datetime object
613
+ The corresponding datetime object
558
614
  """
559
615
  # Add 0.5 to the Julian day to adjust for noon-based Julian day
560
616
  jd_plus = jd + 0.5
@@ -613,13 +669,16 @@ def julian_to_datetime(jd):
613
669
 
614
670
  def get_house_name(house_number: int) -> Houses:
615
671
  """
616
- Returns the name of the house based on its number.
672
+ Convert a house number to its corresponding house name.
617
673
 
618
674
  Args:
619
675
  house_number: House number (1-12)
620
676
 
621
677
  Returns:
622
- Name of the house
678
+ The house name
679
+
680
+ Raises:
681
+ ValueError: If house_number is not in range 1-12
623
682
  """
624
683
  house_names: dict[int, Houses] = {
625
684
  1: "First_House",
@@ -645,13 +704,16 @@ def get_house_name(house_number: int) -> Houses:
645
704
 
646
705
  def get_house_number(house_name: Houses) -> int:
647
706
  """
648
- Returns the number of the house based on its name.
707
+ Convert a house name to its corresponding house number.
649
708
 
650
709
  Args:
651
- house_name: Name of the house
710
+ house_name: The house name
652
711
 
653
712
  Returns:
654
713
  House number (1-12)
714
+
715
+ Raises:
716
+ ValueError: If house_name is not recognized
655
717
  """
656
718
  house_numbers: dict[Houses, int] = {
657
719
  "First_House": 1,
@@ -677,14 +739,14 @@ def get_house_number(house_name: Houses) -> int:
677
739
 
678
740
  def find_common_active_points(first_points: list[AstrologicalPoint], second_points: list[AstrologicalPoint]) -> list[AstrologicalPoint]:
679
741
  """
680
- Find only the elements that are present in both lists.
742
+ Find astrological points that appear in both input lists.
681
743
 
682
744
  Args:
683
- first_points: List of astrological points
684
- second_points: List of astrological points
745
+ first_points: First list of astrological points
746
+ second_points: Second list of astrological points
685
747
 
686
748
  Returns:
687
- List of elements common to both lists (without duplicates, order not guaranteed).
749
+ List of points common to both input lists (without duplicates)
688
750
  """
689
751
  common_points = list(set(first_points) & set(second_points))
690
752
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kerykeion
3
- Version: 5.0.0a10
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
 
@@ -0,0 +1,50 @@
1
+ kerykeion/__init__.py,sha256=WTTZBOe40IuvcINRRrsqinEkTFzaJNbPcZ8iO6F3fvw,1274
2
+ kerykeion/astrological_subject_factory.py,sha256=TrnZ_jIphKzu7NqxlL5vp5JELzuPgxIz1KtrW7W2-5M,83655
3
+ kerykeion/composite_subject_factory.py,sha256=sqs7CiP_3lGI9-FeRFMFL7PIXTlSUaXA9pUDI_5zPZw,17124
4
+ kerykeion/ephemeris_data_factory.py,sha256=Iwd8KkBB-WmI8AEwrhe9ze8dicA5kvpflT_yQD9XkAY,20111
5
+ kerykeion/fetch_geonames.py,sha256=SPI4fSvD59C-IVpaoeOHuD7_kjGbTLo2fypO2x57-p4,5432
6
+ kerykeion/planetary_return_factory.py,sha256=7fwfjhJATFmUNJkIqgaz07sWtpwHPjHvF2oFyPGfga4,37246
7
+ kerykeion/relationship_score_factory.py,sha256=kcr0qEA4_2oQ_2g8IcrHgpVEyb9uAm4EmVWJAGsoCtg,11099
8
+ kerykeion/report.py,sha256=dUtI70wUjOouqNE1pf0ZYFY4qme9pR7WQRbs_ExEkjM,3029
9
+ kerykeion/transits_time_range_factory.py,sha256=xFEdOqYINTBluwp-CKeYTJgANlPEeVw4TYMLigiC30M,13392
10
+ kerykeion/utilities.py,sha256=MtVyZ2dbHrJPuDoPKPrkx0MrB83fxcbGtPx87piHCtQ,23471
11
+ kerykeion/aspects/__init__.py,sha256=csJmxvLdBu-bHuW676f3dpY__Qyc6LwRyrpWVTh3n1A,287
12
+ kerykeion/aspects/aspects_factory.py,sha256=09Hm50c5J-OiMwgsoxZXWidCBgZc2gzhwz95MdHJUy4,22664
13
+ kerykeion/aspects/aspects_utils.py,sha256=mOj2AqVGnY2vsGsezPfxI_crPJsN54p8qjpmCk5iupM,3093
14
+ kerykeion/charts/__init__.py,sha256=i9NMZ7LdkllPlqQSi1or9gTobHbROGDKmJhBDO4R0mA,128
15
+ kerykeion/charts/charts_utils.py,sha256=_z-lA7ibIQ5vhr1NxpzJFyPmMp-Sh1iyYxuO56DDO4w,62922
16
+ kerykeion/charts/draw_planets.py,sha256=6S0sCAktZJa7eckb-h1voYbe0H27vL9otcJzA0dqFH0,28167
17
+ kerykeion/charts/kerykeion_chart_svg.py,sha256=pNSmGZYtFGSx17EKcdSSYunP_oKy3xLSiq_CmbGz8Fs,97285
18
+ kerykeion/charts/templates/aspect_grid_only.xml,sha256=lBHBj5bS5klGnv7QMuFxQjhlE6VZRaOgW93akLgRjX4,70055
19
+ kerykeion/charts/templates/chart.xml,sha256=r3a_csMqcoqeOnDA3YCD-iUxdqgRw5GV1GOf1Cp0e_E,79940
20
+ kerykeion/charts/templates/wheel_only.xml,sha256=X2-bwmEvQnZcM5Om7JXIWZSoSmFLAm4sY31heSq5u1k,71388
21
+ kerykeion/charts/themes/classic.css,sha256=LYYYWQHNG7-vuPCq8F2EPl3LauWXVrY3Q_tpwM0klgo,4660
22
+ kerykeion/charts/themes/dark-high-contrast.css,sha256=YW5X5-M0dz5Vy2oz-JyDNXJYHSmV83lYCodydC-KS1A,7506
23
+ kerykeion/charts/themes/dark.css,sha256=XVspznDRNMXsFzk7hY7IB7AI58alPAV_-CgV3gCKyzg,7581
24
+ kerykeion/charts/themes/light.css,sha256=5eyUzhVlRjG6lPHKnprLum0HuRtPIJhMBzpGfzoTjnQ,7590
25
+ kerykeion/charts/themes/strawberry.css,sha256=UtcfRsCT-M9OZs_SoclWGZ0jDJiWvQjHTeI4M1jf7pQ,8314
26
+ kerykeion/house_comparison/__init__.py,sha256=6FYHyQY3nUJifZ2kEVCHB8cN3TjFA1q2yhmeRwJlias,238
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
30
+ kerykeion/kr_types/__init__.py,sha256=dePcQY5rrgtUENhqnjcVx6j7iQJPo_1rmD0bLeIO3HA,1384
31
+ kerykeion/kr_types/chart_types.py,sha256=ofMYk7NRalSsdQcLVkpCbOb-dhdjYHEqIb_WPLtD0rM,2429
32
+ kerykeion/kr_types/kerykeion_exception.py,sha256=vTYdwj_mL-Q-MqHJvEzzBXxQ5YI2kAwUC6ImoWxMKXc,454
33
+ kerykeion/kr_types/kr_literals.py,sha256=4kJhzm_0LERiJEJks0KgDyThueMZj_F1OK2Far5SMZc,4870
34
+ kerykeion/kr_types/kr_models.py,sha256=5wG3bh7EvCD0FTYe-W2e8jNLK408f3JQQhda6DVrOnw,14180
35
+ kerykeion/kr_types/settings_models.py,sha256=Llosnvw-6NHJMbdKltPHQDLR-Ltn7ZpWkjEbLJ2C6AY,17488
36
+ kerykeion/settings/__init__.py,sha256=NYCwcvEfn9qJ498fv1H_Gix8e-crJ3CruV13A-e2CnI,134
37
+ kerykeion/settings/config_constants.py,sha256=hxDZnFKWFhGrYMejDISbYT-phUk1Qqfvt-4wBG79rGA,2233
38
+ kerykeion/settings/kerykeion_settings.py,sha256=umd8TZy-8ywowsd4TTkhwxSLLyX3xYj3A1zvNsTV_Y8,2955
39
+ kerykeion/settings/kr.config.json,sha256=bvvhi8W-u9YHTbg9O8UyfOwclhLd8Mh8oobI1qHIgp4,58497
40
+ kerykeion/settings/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
+ kerykeion/settings/legacy/legacy_celestial_points_settings.py,sha256=YMvHhY8IQ_nNHf1-9JCSgRzTMQJaxXZfROztEhlP4Ac,6870
42
+ kerykeion/settings/legacy/legacy_chart_aspects_settings.py,sha256=tO4tgPgPP07_wu9f8SXyJQ9WrTh3iWz4YvBS2axCGU8,1650
43
+ kerykeion/settings/legacy/legacy_color_settings.py,sha256=gBUmGSNvvLzRYbdVtzwTDnMwWoh4tOCyT_9Q6aQRv_s,2620
44
+ kerykeion/sweph/README.md,sha256=L7FtNAJTWtrZNGKa8MX87SjduFYPYxwWhaI5fmtzNZo,73
45
+ kerykeion/sweph/seas_18.se1,sha256=X9nCqhZU43wJpq61WAdueVQJt9xL2UjrwPqn1Kdoa1s,223002
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,,