kerykeion 5.0.0a9__py3-none-any.whl → 5.1.8__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 (79) hide show
  1. kerykeion/__init__.py +50 -9
  2. kerykeion/aspects/__init__.py +5 -2
  3. kerykeion/aspects/aspects_factory.py +568 -0
  4. kerykeion/aspects/aspects_utils.py +78 -11
  5. kerykeion/astrological_subject_factory.py +1032 -275
  6. kerykeion/backword.py +820 -0
  7. kerykeion/chart_data_factory.py +552 -0
  8. kerykeion/charts/chart_drawer.py +2661 -0
  9. kerykeion/charts/charts_utils.py +652 -399
  10. kerykeion/charts/draw_planets.py +603 -353
  11. kerykeion/charts/templates/aspect_grid_only.xml +326 -198
  12. kerykeion/charts/templates/chart.xml +306 -256
  13. kerykeion/charts/templates/wheel_only.xml +330 -200
  14. kerykeion/charts/themes/black-and-white.css +148 -0
  15. kerykeion/charts/themes/classic.css +11 -0
  16. kerykeion/charts/themes/dark-high-contrast.css +11 -0
  17. kerykeion/charts/themes/dark.css +11 -0
  18. kerykeion/charts/themes/light.css +11 -0
  19. kerykeion/charts/themes/strawberry.css +10 -0
  20. kerykeion/composite_subject_factory.py +232 -13
  21. kerykeion/ephemeris_data_factory.py +443 -0
  22. kerykeion/fetch_geonames.py +78 -21
  23. kerykeion/house_comparison/__init__.py +4 -1
  24. kerykeion/house_comparison/house_comparison_factory.py +52 -19
  25. kerykeion/house_comparison/house_comparison_utils.py +37 -9
  26. kerykeion/kr_types/__init__.py +66 -6
  27. kerykeion/kr_types/chart_template_model.py +20 -0
  28. kerykeion/kr_types/kerykeion_exception.py +15 -9
  29. kerykeion/kr_types/kr_literals.py +14 -160
  30. kerykeion/kr_types/kr_models.py +14 -291
  31. kerykeion/kr_types/settings_models.py +15 -167
  32. kerykeion/planetary_return_factory.py +545 -40
  33. kerykeion/relationship_score_factory.py +137 -63
  34. kerykeion/report.py +749 -64
  35. kerykeion/schemas/__init__.py +106 -0
  36. kerykeion/schemas/chart_template_model.py +367 -0
  37. kerykeion/schemas/kerykeion_exception.py +20 -0
  38. kerykeion/schemas/kr_literals.py +181 -0
  39. kerykeion/schemas/kr_models.py +603 -0
  40. kerykeion/schemas/settings_models.py +188 -0
  41. kerykeion/settings/__init__.py +20 -1
  42. kerykeion/settings/chart_defaults.py +444 -0
  43. kerykeion/settings/config_constants.py +88 -12
  44. kerykeion/settings/kerykeion_settings.py +32 -75
  45. kerykeion/settings/translation_strings.py +1499 -0
  46. kerykeion/settings/translations.py +74 -0
  47. kerykeion/sweph/ast136/s136108s.se1 +0 -0
  48. kerykeion/sweph/ast136/s136199s.se1 +0 -0
  49. kerykeion/sweph/ast136/s136472s.se1 +0 -0
  50. kerykeion/sweph/ast28/se28978s.se1 +0 -0
  51. kerykeion/sweph/ast50/se50000s.se1 +0 -0
  52. kerykeion/sweph/ast90/se90377s.se1 +0 -0
  53. kerykeion/sweph/ast90/se90482s.se1 +0 -0
  54. kerykeion/sweph/sefstars.txt +1602 -0
  55. kerykeion/transits_time_range_factory.py +302 -0
  56. kerykeion/utilities.py +289 -204
  57. kerykeion-5.1.8.dist-info/METADATA +1793 -0
  58. kerykeion-5.1.8.dist-info/RECORD +63 -0
  59. kerykeion/aspects/natal_aspects.py +0 -181
  60. kerykeion/aspects/synastry_aspects.py +0 -141
  61. kerykeion/aspects/transits_time_range.py +0 -41
  62. kerykeion/charts/draw_planets_v2.py +0 -649
  63. kerykeion/charts/draw_planets_v3.py +0 -679
  64. kerykeion/charts/kerykeion_chart_svg.py +0 -2038
  65. kerykeion/enums.py +0 -57
  66. kerykeion/ephemeris_data.py +0 -238
  67. kerykeion/house_comparison/house_comparison_models.py +0 -38
  68. kerykeion/kr_types/chart_types.py +0 -106
  69. kerykeion/settings/kr.config.json +0 -1304
  70. kerykeion/settings/legacy/__init__.py +0 -0
  71. kerykeion/settings/legacy/legacy_celestial_points_settings.py +0 -299
  72. kerykeion/settings/legacy/legacy_chart_aspects_settings.py +0 -71
  73. kerykeion/settings/legacy/legacy_color_settings.py +0 -42
  74. kerykeion/transits_time_range.py +0 -128
  75. kerykeion-5.0.0a9.dist-info/METADATA +0 -636
  76. kerykeion-5.0.0a9.dist-info/RECORD +0 -55
  77. kerykeion-5.0.0a9.dist-info/entry_points.txt +0 -2
  78. {kerykeion-5.0.0a9.dist-info → kerykeion-5.1.8.dist-info}/WHEEL +0 -0
  79. {kerykeion-5.0.0a9.dist-info → kerykeion-5.1.8.dist-info}/licenses/LICENSE +0 -0
@@ -1,32 +1,206 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
- Module for generating Planetary Return charts using the Swiss Ephemeris.
4
-
5
- This module provides the PlanetaryReturnFactory class, which computes
6
- the return times and chart data for solar and lunar returns of a natal
7
- astrological subject.
3
+ Planetary Return Factory Module
4
+
5
+ This module provides the PlanetaryReturnFactory class for calculating and generating
6
+ comprehensive planetary return charts, specifically Solar and Lunar returns. It leverages
7
+ the Swiss Ephemeris library for precise astronomical calculations to determine exact
8
+ return moments and create complete astrological chart data.
9
+
10
+ Key Features:
11
+ - Solar Return calculations (Sun's annual return to natal position)
12
+ - Lunar Return calculations (Moon's monthly return to natal position)
13
+ - Multiple date input formats (ISO datetime, year-based, month/year-based)
14
+ - Flexible location handling (online geocoding or manual coordinates)
15
+ - Complete astrological chart generation for return moments
16
+ - Integration with Geonames service for location data
17
+ - Timezone-aware calculations with UTC precision
18
+
19
+ A planetary return occurs when a planet returns to the exact degree and minute
20
+ it occupied at the time of birth. Solar returns happen approximately once per year
21
+ and are widely used for annual forecasting, while Lunar returns occur roughly
22
+ every 27-29 days and are used for monthly analysis and timing.
23
+
24
+ The factory creates complete AstrologicalSubject instances for the calculated
25
+ return moments, enabling full chart analysis including planetary positions,
26
+ aspects, house cusps, and all other astrological features.
27
+
28
+ Classes:
29
+ PlanetaryReturnFactory: Main factory class for calculating planetary returns
30
+
31
+ Dependencies:
32
+ - swisseph: Swiss Ephemeris library for astronomical calculations
33
+ - kerykeion.AstrologicalSubjectFactory: For creating complete chart data
34
+ - kerykeion.fetch_geonames: For online location data retrieval
35
+ - kerykeion.utilities: For date/time conversions and astronomical functions
36
+ - kerykeion.schemas: For type definitions and model structures
37
+
38
+ Example:
39
+ Basic Solar Return calculation for a specific year:
40
+
41
+ >>> from kerykeion import AstrologicalSubjectFactory
42
+ >>> from kerykeion.planetary_return_factory import PlanetaryReturnFactory
43
+ >>>
44
+ >>> # Create natal chart
45
+ >>> subject = AstrologicalSubjectFactory.from_birth_data(
46
+ ... name="John Doe",
47
+ ... year=1990, month=6, day=15,
48
+ ... hour=12, minute=30,
49
+ ... lat=40.7128, lng=-74.0060,
50
+ ... tz_str="America/New_York"
51
+ ... )
52
+ >>>
53
+ >>> # Create return calculator for New York location
54
+ >>> calculator = PlanetaryReturnFactory(
55
+ ... subject,
56
+ ... city="New York",
57
+ ... nation="US",
58
+ ... online=True
59
+ ... )
60
+ >>>
61
+ >>> # Calculate Solar Return for 2024
62
+ >>> solar_return = calculator.next_return_from_year(2024, "Solar")
63
+ >>> print(f"Solar Return: {solar_return.iso_formatted_local_datetime}")
64
+ >>> print(f"Sun position: {solar_return.sun.abs_pos}°")
65
+
66
+ Author: Giacomo Battaglia
67
+ Copyright: (C) 2025 Kerykeion Project
68
+ License: AGPL-3.0
8
69
  """
9
70
  import logging
10
71
  import swisseph as swe
11
72
 
12
73
  from datetime import datetime, timezone
13
- from typing import Optional, Union
74
+ from typing import Union
14
75
 
15
- from kerykeion.kr_types import KerykeionException
76
+ from kerykeion.schemas import KerykeionException
16
77
  from kerykeion.fetch_geonames import FetchGeonames
17
78
  from kerykeion.utilities import julian_to_datetime, datetime_to_julian
18
79
  from kerykeion.astrological_subject_factory import (
19
80
  GEONAMES_DEFAULT_USERNAME_WARNING,
20
81
  DEFAULT_GEONAMES_CACHE_EXPIRE_AFTER_DAYS,
82
+ DEFAULT_GEONAMES_USERNAME,
21
83
  )
22
84
  from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
23
- from kerykeion.kr_types.kr_literals import ReturnType
24
- from kerykeion.kr_types.kr_models import PlanetReturnModel, AstrologicalSubjectModel
85
+ from kerykeion.schemas.kr_literals import ReturnType
86
+ from kerykeion.schemas.kr_models import PlanetReturnModel, AstrologicalSubjectModel
25
87
 
26
88
 
27
89
  class PlanetaryReturnFactory:
28
90
  """
29
- Calculator class to generate Solar and Lunar Return charts.
91
+ A factory class for calculating and generating planetary return charts.
92
+
93
+ This class specializes in computing precise planetary return moments using the Swiss
94
+ Ephemeris library and creating complete astrological charts for those calculated times.
95
+ It supports both Solar Returns (annual) and Lunar Returns (monthly), providing
96
+ comprehensive astrological analysis capabilities for timing and forecasting applications.
97
+
98
+ Planetary returns are fundamental concepts in predictive astrology:
99
+ - Solar Returns: Occur when the Sun returns to its exact natal position (~365.25 days)
100
+ - Lunar Returns: Occur when the Moon returns to its exact natal position (~27-29 days)
101
+
102
+ The factory handles complex astronomical calculations automatically, including:
103
+ - Precise celestial mechanics computations
104
+ - Timezone conversions and UTC coordination
105
+ - Location-based calculations for return chart casting
106
+ - Integration with online geocoding services
107
+ - Complete chart generation with all astrological points
108
+
109
+ Args:
110
+ subject (AstrologicalSubjectModel): The natal astrological subject for whom
111
+ returns are calculated. Must contain complete birth data including
112
+ planetary positions at birth.
113
+ city (Optional[str]): City name for return chart location. Required when
114
+ using online mode for location data retrieval.
115
+ nation (Optional[str]): Nation/country code for return chart location.
116
+ Required when using online mode (e.g., "US", "GB", "FR").
117
+ lng (Optional[Union[int, float]]): Geographic longitude in decimal degrees
118
+ for return chart location. Positive values for East, negative for West.
119
+ Required when using offline mode.
120
+ lat (Optional[Union[int, float]]): Geographic latitude in decimal degrees
121
+ for return chart location. Positive values for North, negative for South.
122
+ Required when using offline mode.
123
+ tz_str (Optional[str]): Timezone identifier for return chart location
124
+ (e.g., "America/New_York", "Europe/London", "Asia/Tokyo").
125
+ Required when using offline mode.
126
+ online (bool, optional): Whether to fetch location data online via Geonames
127
+ service. When True, requires city, nation, and geonames_username.
128
+ When False, requires lng, lat, and tz_str. Defaults to True.
129
+ geonames_username (Optional[str]): Username for Geonames API access.
130
+ Required when online=True and coordinates are not provided.
131
+ Register at http://www.geonames.org/login for free account.
132
+ cache_expire_after_days (int, optional): Number of days to cache Geonames
133
+ location data before refreshing. Defaults to system setting.
134
+ altitude (Optional[Union[float, int]]): Elevation above sea level in meters
135
+ for the return chart location. Reserved for future astronomical
136
+ calculations. Defaults to None.
137
+
138
+ Raises:
139
+ KerykeionException: If required location parameters are missing for the
140
+ chosen mode (online/offline).
141
+ KerykeionException: If Geonames API fails to retrieve location data.
142
+ KerykeionException: If online mode is used without proper API credentials.
143
+
144
+ Attributes:
145
+ subject (AstrologicalSubjectModel): The natal subject for calculations.
146
+ city (Optional[str]): Return chart city name.
147
+ nation (Optional[str]): Return chart nation code.
148
+ lng (float): Return chart longitude coordinate.
149
+ lat (float): Return chart latitude coordinate.
150
+ tz_str (str): Return chart timezone identifier.
151
+ online (bool): Location data retrieval mode.
152
+ city_data (Optional[dict]): Cached location data from Geonames.
153
+
154
+ Examples:
155
+ Online mode with automatic location lookup:
156
+
157
+ >>> subject = AstrologicalSubjectFactory.from_birth_data(
158
+ ... name="Alice", year=1985, month=3, day=21,
159
+ ... hour=14, minute=30, lat=51.5074, lng=-0.1278,
160
+ ... tz_str="Europe/London"
161
+ ... )
162
+ >>> factory = PlanetaryReturnFactory(
163
+ ... subject,
164
+ ... city="London",
165
+ ... nation="GB",
166
+ ... online=True,
167
+ ... geonames_username="your_username"
168
+ ... )
169
+
170
+ Offline mode with manual coordinates:
171
+
172
+ >>> factory = PlanetaryReturnFactory(
173
+ ... subject,
174
+ ... lng=-74.0060,
175
+ ... lat=40.7128,
176
+ ... tz_str="America/New_York",
177
+ ... online=False
178
+ ... )
179
+
180
+ Different location for return chart:
181
+
182
+ >>> # Calculate return as if living in a different city
183
+ >>> factory = PlanetaryReturnFactory(
184
+ ... natal_subject, # Born in London
185
+ ... city="Paris", # But living in Paris
186
+ ... nation="FR",
187
+ ... online=True
188
+ ... )
189
+
190
+ Use Cases:
191
+ - Annual Solar Return charts for yearly forecasting
192
+ - Monthly Lunar Return charts for timing analysis
193
+ - Relocation returns for different geographic locations
194
+ - Research into planetary cycle effects
195
+ - Astrological consultation and chart analysis
196
+ - Educational demonstrations of celestial mechanics
197
+
198
+ Note:
199
+ Return calculations use the exact degree and minute of natal planetary
200
+ positions. The resulting charts are cast for the precise moment when
201
+ the transiting planet reaches this position, which may not align with
202
+ calendar dates (especially for Solar Returns, which can occur on
203
+ different dates depending on leap years and location).
30
204
  """
31
205
 
32
206
  def __init__(
@@ -45,19 +219,99 @@ class PlanetaryReturnFactory:
45
219
  ):
46
220
 
47
221
  """
48
- Initialize a PlanetaryReturnFactory instance.
222
+ Initialize a PlanetaryReturnFactory instance with location and configuration settings.
223
+
224
+ This constructor sets up the factory with all necessary parameters for calculating
225
+ planetary returns at a specified location. It supports both online mode (with
226
+ automatic geocoding via Geonames) and offline mode (with manual coordinates).
227
+
228
+ The factory validates input parameters based on the chosen mode and automatically
229
+ retrieves missing location data when operating online. All location parameters
230
+ are stored and used for casting return charts at the exact calculated moments.
49
231
 
50
232
  Args:
51
- subject (AstrologicalSubject): The natal astrological subject.
52
- city (Optional[str]): City name for return location (online mode).
53
- nation (Optional[str]): Nation code for return location (online mode).
54
- lng (Optional[Union[int, float]]): Longitude for return location.
55
- lat (Optional[Union[int, float]]): Latitude for return location.
56
- tz_str (Optional[str]): Timezone string for return location.
57
- online (bool): Whether to fetch location data online via Geonames.
58
- geonames_username (Optional[str]): Username for Geonames API.
59
- cache_expire_after_days (int): Days to expire Geonames cache.
60
- altitude (Optional[float]): Altitude of the location (reserved for future use).
233
+ subject (AstrologicalSubjectModel): The natal astrological subject containing
234
+ birth data and planetary positions. This subject's natal planetary
235
+ positions serve as reference points for calculating returns.
236
+ city (Optional[str]): City name for the return chart location. Must be a
237
+ recognizable city name for Geonames geocoding when using online mode.
238
+ Examples: "New York", "London", "Tokyo", "Paris".
239
+ nation (Optional[str]): Country or nation code for the return chart location.
240
+ Use ISO country codes for best results (e.g., "US", "GB", "JP", "FR").
241
+ Required when online=True.
242
+ lng (Optional[Union[int, float]]): Geographic longitude coordinate in decimal
243
+ degrees for return chart location. Range: -180.0 to +180.0.
244
+ Positive values represent East longitude, negative values West longitude.
245
+ Required when online=False.
246
+ lat (Optional[Union[int, float]]): Geographic latitude coordinate in decimal
247
+ degrees for return chart location. Range: -90.0 to +90.0.
248
+ Positive values represent North latitude, negative values South latitude.
249
+ Required when online=False.
250
+ tz_str (Optional[str]): Timezone identifier string for return chart location.
251
+ Must be a valid timezone from the IANA Time Zone Database
252
+ (e.g., "America/New_York", "Europe/London", "Asia/Tokyo").
253
+ Required when online=False.
254
+ online (bool, optional): Location data retrieval mode. When True, uses
255
+ Geonames web service to automatically fetch coordinates and timezone
256
+ from city/nation parameters. When False, uses manually provided
257
+ coordinates and timezone. Defaults to True.
258
+ geonames_username (Optional[str]): Username for Geonames API access.
259
+ Required when online=True and coordinates are not manually provided.
260
+ Free accounts available at http://www.geonames.org/login.
261
+ If None and required, uses default username with warning.
262
+ cache_expire_after_days (int, optional): Number of days to cache Geonames
263
+ location data locally before requiring refresh. Helps reduce API
264
+ calls and improve performance for repeated calculations.
265
+ Defaults to system configuration value.
266
+ altitude (Optional[Union[float, int]]): Elevation above sea level in meters
267
+ for the return chart location. Currently reserved for future use in
268
+ advanced astronomical calculations. Defaults to None.
269
+
270
+ Raises:
271
+ KerykeionException: If city is not provided when online=True.
272
+ KerykeionException: If nation is not provided when online=True.
273
+ KerykeionException: If coordinates (lat/lng) are not provided when online=False.
274
+ KerykeionException: If timezone (tz_str) is not provided when online=False.
275
+ KerykeionException: If Geonames API fails to retrieve valid location data.
276
+ KerykeionException: If required parameters are missing for the chosen mode.
277
+
278
+ Examples:
279
+ Initialize with online geocoding:
280
+
281
+ >>> factory = PlanetaryReturnFactory(
282
+ ... subject,
283
+ ... city="San Francisco",
284
+ ... nation="US",
285
+ ... online=True,
286
+ ... geonames_username="your_username"
287
+ ... )
288
+
289
+ Initialize with manual coordinates:
290
+
291
+ >>> factory = PlanetaryReturnFactory(
292
+ ... subject,
293
+ ... lng=-122.4194,
294
+ ... lat=37.7749,
295
+ ... tz_str="America/Los_Angeles",
296
+ ... online=False
297
+ ... )
298
+
299
+ Initialize with mixed parameters (coordinates override online lookup):
300
+
301
+ >>> factory = PlanetaryReturnFactory(
302
+ ... subject,
303
+ ... city="Custom Location",
304
+ ... lng=-74.0060,
305
+ ... lat=40.7128,
306
+ ... tz_str="America/New_York",
307
+ ... online=False
308
+ ... )
309
+
310
+ Note:
311
+ - When both online and manual coordinates are provided, offline mode takes precedence
312
+ - Geonames cache helps reduce API calls for frequently used locations
313
+ - Timezone accuracy is crucial for precise return calculations
314
+ - Location parameters affect house cusps and angular positions in return charts
61
315
  """
62
316
  # Store basic configuration
63
317
  self.subject = subject
@@ -118,10 +372,10 @@ class PlanetaryReturnFactory:
118
372
  self.city_data: dict[str, str] = geonames.get_serialized_data()
119
373
 
120
374
  if (
121
- not "countryCode" in self.city_data
122
- or not "timezonestr" in self.city_data
123
- or not "lat" in self.city_data
124
- or not "lng" in self.city_data
375
+ "countryCode" not in self.city_data
376
+ or "timezonestr" not in self.city_data
377
+ or "lat" not in self.city_data
378
+ or "lng" not in self.city_data
125
379
  ):
126
380
  raise KerykeionException("No data found for this city, try again! Maybe check your connection?")
127
381
 
@@ -136,13 +390,95 @@ class PlanetaryReturnFactory:
136
390
  return_type: ReturnType
137
391
  ) -> PlanetReturnModel:
138
392
  """
139
- Get the next Return for the provided ISO-formatted time.
393
+ Calculate the next planetary return occurring after a specified ISO-formatted datetime.
394
+
395
+ This method computes the exact moment when the specified planet (Sun or Moon) returns
396
+ to its natal position, starting the search from the provided datetime. It uses precise
397
+ Swiss Ephemeris calculations to determine the exact return moment and generates a
398
+ complete astrological chart for that calculated time.
399
+
400
+ The calculation process:
401
+ 1. Converts the ISO datetime to Julian Day format for astronomical calculations
402
+ 2. Uses Swiss Ephemeris functions (solcross_ut/mooncross_ut) to find the exact
403
+ return moment when the planet reaches its natal degree and minute
404
+ 3. Creates a complete AstrologicalSubject instance for the calculated return time
405
+ 4. Returns a comprehensive PlanetReturnModel with all chart data
140
406
 
141
407
  Args:
142
- iso_formatted_time (str): ISO-formatted datetime string.
408
+ iso_formatted_time (str): Starting datetime in ISO format for the search.
409
+ Must be a valid ISO 8601 datetime string (e.g., "2024-01-15T10:30:00"
410
+ or "2024-01-15T10:30:00+00:00"). The method will find the next return
411
+ occurring after this moment.
412
+ return_type (ReturnType): Type of planetary return to calculate.
413
+ Must be either "Solar" for Sun returns or "Lunar" for Moon returns.
414
+ This determines which planet's return cycle to compute.
143
415
 
144
416
  Returns:
145
- PlanetReturnModel: Pydantic model containing the return chart data.
417
+ PlanetReturnModel: A comprehensive Pydantic model containing complete
418
+ astrological chart data for the calculated return moment, including:
419
+ - Exact return datetime (UTC and local timezone)
420
+ - All planetary positions at the return moment
421
+ - House cusps and angles for the return location
422
+ - Complete astrological subject data with all calculated points
423
+ - Return type identifier and subject name
424
+ - Julian Day Number for the return moment
425
+
426
+ Raises:
427
+ KerykeionException: If return_type is not "Solar" or "Lunar".
428
+ ValueError: If iso_formatted_time is not a valid ISO datetime format.
429
+ SwissEphException: If Swiss Ephemeris calculations fail due to invalid
430
+ date ranges or astronomical calculation errors.
431
+
432
+ Examples:
433
+ Calculate next Solar Return after a specific date:
434
+
435
+ >>> factory = PlanetaryReturnFactory(subject, ...)
436
+ >>> solar_return = factory.next_return_from_iso_formatted_time(
437
+ ... "2024-06-15T12:00:00",
438
+ ... "Solar"
439
+ ... )
440
+ >>> print(f"Solar Return: {solar_return.iso_formatted_local_datetime}")
441
+ >>> print(f"Sun position: {solar_return.sun.abs_pos}°")
442
+
443
+ Calculate next Lunar Return with timezone:
444
+
445
+ >>> lunar_return = factory.next_return_from_iso_formatted_time(
446
+ ... "2024-01-01T00:00:00+00:00",
447
+ ... "Lunar"
448
+ ... )
449
+ >>> print(f"Moon return in {lunar_return.tz_str}")
450
+ >>> print(f"Return occurs: {lunar_return.iso_formatted_local_datetime}")
451
+
452
+ Access complete chart data from return:
453
+
454
+ >>> return_chart = factory.next_return_from_iso_formatted_time(
455
+ ... datetime.now().isoformat(),
456
+ ... "Solar"
457
+ ... )
458
+ >>> # Access all planetary positions
459
+ >>> for planet in return_chart.planets_list:
460
+ ... print(f"{planet.name}: {planet.abs_pos}° in {planet.sign}")
461
+ >>> # Access house cusps
462
+ >>> for house in return_chart.houses_list:
463
+ ... print(f"House {house.number}: {house.abs_pos}°")
464
+
465
+ Technical Notes:
466
+ - Solar returns typically occur within 1-2 days of the natal birthday
467
+ - Lunar returns occur approximately every 27.3 days (sidereal month)
468
+ - Return moments are calculated to the second for maximum precision
469
+ - The method accounts for leap years and varying orbital speeds
470
+ - Return charts use the factory's configured location, not the natal location
471
+
472
+ Use Cases:
473
+ - Annual birthday return chart calculations
474
+ - Monthly lunar return timing for astrological consultation
475
+ - Research into planetary cycle patterns and timing
476
+ - Forecasting and predictive astrology applications
477
+ - Educational demonstrations of astronomical cycles
478
+
479
+ See Also:
480
+ next_return_from_year(): Simplified interface for yearly calculations
481
+ next_return_from_month_and_year(): Monthly calculation interface
146
482
  """
147
483
 
148
484
  date = datetime.fromisoformat(iso_formatted_time)
@@ -150,11 +486,15 @@ class PlanetaryReturnFactory:
150
486
 
151
487
  return_julian_date = None
152
488
  if return_type == "Solar":
489
+ if self.subject.sun is None:
490
+ raise KerykeionException("Sun position is required for Solar return but is not available in the subject.")
153
491
  return_julian_date = swe.solcross_ut(
154
492
  self.subject.sun.abs_pos,
155
493
  julian_day,
156
494
  )
157
495
  elif return_type == "Lunar":
496
+ if self.subject.moon is None:
497
+ raise KerykeionException("Moon position is required for Lunar return but is not available in the subject.")
158
498
  return_julian_date = swe.mooncross_ut(
159
499
  self.subject.moon.abs_pos,
160
500
  julian_day,
@@ -192,16 +532,84 @@ class PlanetaryReturnFactory:
192
532
  return_type: ReturnType
193
533
  ) -> PlanetReturnModel:
194
534
  """
195
- Get the next Return for the specified year.
535
+ Calculate the planetary return occurring within a specified year.
536
+
537
+ This is a convenience method that finds the first planetary return (Solar or Lunar)
538
+ that occurs in the given calendar year. It automatically searches from January 1st
539
+ of the specified year and returns the first return found, making it ideal for
540
+ annual forecasting and birthday return calculations.
196
541
 
197
- This method finds the first return that occurs in the given year.
542
+ For Solar Returns, this typically finds the return closest to the natal birthday
543
+ within that year. For Lunar Returns, it finds the first lunar return occurring
544
+ in January of the specified year.
545
+
546
+ The method internally uses next_return_from_iso_formatted_time() with a starting
547
+ point of January 1st at midnight UTC for the specified year.
198
548
 
199
549
  Args:
200
- year (int): The year to search for the return
201
- return_type (ReturnType): The type of return ("Solar" or "Lunar")
550
+ year (int): The calendar year to search for the return. Must be a valid
551
+ year (typically between 1800-2200 for reliable ephemeris data).
552
+ Examples: 2024, 2025, 1990, 2050.
553
+ return_type (ReturnType): The type of planetary return to calculate.
554
+ Must be either "Solar" for Sun returns or "Lunar" for Moon returns.
202
555
 
203
556
  Returns:
204
- PlanetReturnModel: Pydantic model containing the return chart data
557
+ PlanetReturnModel: A comprehensive model containing the return chart data
558
+ for the first return found in the specified year. Includes:
559
+ - Exact return datetime in both UTC and local timezone
560
+ - Complete planetary positions at the return moment
561
+ - House cusps calculated for the factory's configured location
562
+ - All astrological chart features and calculated points
563
+ - Return type and subject identification
564
+
565
+ Raises:
566
+ KerykeionException: If return_type is not "Solar" or "Lunar".
567
+ ValueError: If year is outside the valid range for ephemeris calculations.
568
+ SwissEphException: If astronomical calculations fail for the given year.
569
+
570
+ Examples:
571
+ Calculate Solar Return for 2024:
572
+
573
+ >>> factory = PlanetaryReturnFactory(subject, ...)
574
+ >>> solar_return_2024 = factory.next_return_from_year(2024, "Solar")
575
+ >>> print(f"2024 Solar Return: {solar_return_2024.iso_formatted_local_datetime}")
576
+ >>> print(f"Birthday location: {solar_return_2024.city}, {solar_return_2024.nation}")
577
+
578
+ Calculate first Lunar Return of 2025:
579
+
580
+ >>> lunar_return = factory.next_return_from_year(2025, "Lunar")
581
+ >>> print(f"First 2025 Lunar Return: {lunar_return.iso_formatted_local_datetime}")
582
+
583
+ Compare multiple years:
584
+
585
+ >>> for year in [2023, 2024, 2025]:
586
+ ... solar_return = factory.next_return_from_year(year, "Solar")
587
+ ... print(f"{year}: {solar_return.iso_formatted_local_datetime}")
588
+
589
+ Practical Applications:
590
+ - Annual Solar Return chart casting for birthday forecasting
591
+ - Comparative analysis of return charts across multiple years
592
+ - Research into planetary return timing patterns
593
+ - Automated birthday return calculations for consultation
594
+ - Educational demonstrations of annual astrological cycles
595
+
596
+ Technical Notes:
597
+ - Solar returns in a given year occur near but not exactly on the birthday
598
+ - The exact date can vary by 1-2 days due to leap years and orbital mechanics
599
+ - Lunar returns occur approximately every 27.3 days throughout the year
600
+ - This method finds the chronologically first return in the year
601
+ - Return moment precision is calculated to the second
602
+
603
+ Use Cases:
604
+ - Birthday return chart interpretation
605
+ - Annual astrological forecasting
606
+ - Timing analysis for major life events
607
+ - Comparative return chart studies
608
+ - Astrological consultation preparation
609
+
610
+ See Also:
611
+ next_return_from_month_and_year(): For more specific monthly searches
612
+ next_return_from_iso_formatted_time(): For custom starting dates
205
613
  """
206
614
  # Create datetime for January 1st of the specified year (UTC)
207
615
  start_date = datetime(year, 1, 1, 0, 0, tzinfo=timezone.utc)
@@ -219,18 +627,115 @@ class PlanetaryReturnFactory:
219
627
  return_type: ReturnType
220
628
  ) -> PlanetReturnModel:
221
629
  """
222
- Get the next Return for the specified month and year.
630
+ Calculate the first planetary return occurring in or after a specified month and year.
631
+
632
+ This method provides precise timing control for planetary return calculations by
633
+ searching from the first day of a specific month and year. It's particularly
634
+ useful for finding Lunar Returns in specific months or for Solar Return timing
635
+ when you need to focus on a particular time period within a year.
223
636
 
224
- This method finds the first return that occurs after the first day
225
- of the specified month and year.
637
+ The method searches from the first moment (00:00:00 UTC) of the specified month
638
+ and year, finding the next return that occurs from that point forward. This is
639
+ especially valuable for Lunar Return work, where multiple returns occur per year
640
+ and you need to isolate specific monthly periods.
226
641
 
227
642
  Args:
228
- year (int): The year to search for the return
229
- month (int): The month to search for the return (1-12)
230
- return_type (ReturnType): The type of return ("Solar" or "Lunar")
643
+ year (int): The calendar year to search within. Must be a valid year
644
+ within the ephemeris data range (typically 1800-2200).
645
+ Examples: 2024, 2025, 1990.
646
+ month (int): The month to start the search from. Must be between 1 and 12,
647
+ where 1=January, 2=February, ..., 12=December.
648
+ return_type (ReturnType): The type of planetary return to calculate.
649
+ Must be either "Solar" for Sun returns or "Lunar" for Moon returns.
231
650
 
232
651
  Returns:
233
- PlanetReturnModel: Pydantic model containing the return chart data
652
+ PlanetReturnModel: Comprehensive return chart data for the first return
653
+ found on or after the first day of the specified month and year.
654
+ Contains complete astrological chart information including:
655
+ - Precise return datetime in UTC and local timezone
656
+ - All planetary positions at the return moment
657
+ - House cusps for the factory's configured location
658
+ - Complete astrological subject data with all calculated features
659
+ - Return type identifier and naming information
660
+
661
+ Raises:
662
+ KerykeionException: If month is not between 1 and 12.
663
+ KerykeionException: If return_type is not "Solar" or "Lunar".
664
+ ValueError: If year is outside valid ephemeris calculation range.
665
+ SwissEphException: If astronomical calculations fail.
666
+
667
+ Examples:
668
+ Find Solar Return in birth month:
669
+
670
+ >>> factory = PlanetaryReturnFactory(subject, ...)
671
+ >>> # Subject born in June, find 2024 Solar Return in June
672
+ >>> solar_return = factory.next_return_from_month_and_year(
673
+ ... 2024, 6, "Solar"
674
+ ... )
675
+ >>> print(f"Solar Return: {solar_return.iso_formatted_local_datetime}")
676
+
677
+ Find specific Lunar Return:
678
+
679
+ >>> # Find first Lunar Return in March 2024
680
+ >>> lunar_return = factory.next_return_from_month_and_year(
681
+ ... 2024, 3, "Lunar"
682
+ ... )
683
+ >>> print(f"March 2024 Lunar Return: {lunar_return.iso_formatted_local_datetime}")
684
+
685
+ Monthly Lunar Return tracking:
686
+
687
+ >>> lunar_returns_2024 = []
688
+ >>> for month in range(1, 13):
689
+ ... lunar_return = factory.next_return_from_month_and_year(
690
+ ... 2024, month, "Lunar"
691
+ ... )
692
+ ... lunar_returns_2024.append(lunar_return)
693
+ ... print(f"Month {month}: {lunar_return.iso_formatted_local_datetime}")
694
+
695
+ Seasonal analysis:
696
+
697
+ >>> # Spring Solar Return (if birthday is in spring)
698
+ >>> spring_return = factory.next_return_from_month_and_year(
699
+ ... 2024, 3, "Solar"
700
+ ... )
701
+ >>> # Compare with autumn energy
702
+ >>> autumn_lunar = factory.next_return_from_month_and_year(
703
+ ... 2024, 9, "Lunar"
704
+ ... )
705
+
706
+ Practical Applications:
707
+ - Monthly Lunar Return consultation scheduling
708
+ - Seasonal astrological analysis and timing
709
+ - Comparative study of returns across different months
710
+ - Precise timing for astrological interventions
711
+ - Educational demonstrations of monthly astrological cycles
712
+ - Research into seasonal patterns in planetary returns
713
+
714
+ Technical Notes:
715
+ - Search begins at 00:00:00 UTC on the 1st day of the specified month
716
+ - For Solar Returns, may find the return in a subsequent month if
717
+ the birthday falls late in the specified month of the previous year
718
+ - Lunar Returns typically occur within the specified month due to
719
+ their ~27-day cycle
720
+ - Month validation prevents common input errors
721
+ - All calculations maintain second-level precision
722
+
723
+ Timing Considerations:
724
+ - Solar Returns: Usually occur within 1-2 days of the natal birthday
725
+ - Lunar Returns: Occur approximately every 27.3 days
726
+ - The method finds the chronologically first return from the start date
727
+ - Timezone differences can affect which calendar day the return occurs
728
+
729
+ Use Cases:
730
+ - Monthly return chart consultations
731
+ - Timing specific astrological work or rituals
732
+ - Research into monthly astrological patterns
733
+ - Educational calendar planning for astrological courses
734
+ - Comparative return chart analysis
735
+
736
+ See Also:
737
+ next_return_from_year(): For annual return calculations
738
+ next_return_from_iso_formatted_time(): For custom date searches
234
739
  """
235
740
  # Validate month input
236
741
  if month < 1 or month > 12: