kerykeion 4.18.3__py3-none-any.whl → 5.1.9__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.
- kerykeion/__init__.py +56 -11
- kerykeion/aspects/__init__.py +7 -4
- kerykeion/aspects/aspects_factory.py +568 -0
- kerykeion/aspects/aspects_utils.py +86 -13
- kerykeion/astrological_subject_factory.py +1901 -0
- kerykeion/backword.py +820 -0
- kerykeion/chart_data_factory.py +552 -0
- kerykeion/charts/__init__.py +2 -2
- kerykeion/charts/chart_drawer.py +2794 -0
- kerykeion/charts/charts_utils.py +1066 -309
- kerykeion/charts/draw_planets.py +602 -351
- kerykeion/charts/templates/aspect_grid_only.xml +337 -193
- kerykeion/charts/templates/chart.xml +441 -240
- kerykeion/charts/templates/wheel_only.xml +365 -211
- kerykeion/charts/themes/black-and-white.css +148 -0
- kerykeion/charts/themes/classic.css +107 -76
- kerykeion/charts/themes/dark-high-contrast.css +145 -107
- kerykeion/charts/themes/dark.css +146 -107
- kerykeion/charts/themes/light.css +146 -103
- kerykeion/charts/themes/strawberry.css +158 -0
- kerykeion/composite_subject_factory.py +408 -0
- kerykeion/ephemeris_data_factory.py +443 -0
- kerykeion/fetch_geonames.py +81 -21
- kerykeion/house_comparison/__init__.py +6 -0
- kerykeion/house_comparison/house_comparison_factory.py +103 -0
- kerykeion/house_comparison/house_comparison_utils.py +126 -0
- kerykeion/kr_types/__init__.py +66 -6
- kerykeion/kr_types/chart_template_model.py +20 -0
- kerykeion/kr_types/kerykeion_exception.py +15 -9
- kerykeion/kr_types/kr_literals.py +14 -106
- kerykeion/kr_types/kr_models.py +14 -179
- kerykeion/kr_types/settings_models.py +15 -152
- kerykeion/planetary_return_factory.py +805 -0
- kerykeion/relationship_score_factory.py +301 -0
- kerykeion/report.py +750 -65
- kerykeion/schemas/__init__.py +106 -0
- kerykeion/schemas/chart_template_model.py +367 -0
- kerykeion/schemas/kerykeion_exception.py +20 -0
- kerykeion/schemas/kr_literals.py +181 -0
- kerykeion/schemas/kr_models.py +603 -0
- kerykeion/schemas/settings_models.py +188 -0
- kerykeion/settings/__init__.py +20 -1
- kerykeion/settings/chart_defaults.py +444 -0
- kerykeion/settings/config_constants.py +152 -0
- kerykeion/settings/kerykeion_settings.py +36 -61
- kerykeion/settings/translation_strings.py +1499 -0
- kerykeion/settings/translations.py +74 -0
- kerykeion/sweph/ast136/s136108s.se1 +0 -0
- kerykeion/sweph/ast136/s136199s.se1 +0 -0
- kerykeion/sweph/ast136/s136472s.se1 +0 -0
- kerykeion/sweph/ast28/se28978s.se1 +0 -0
- kerykeion/sweph/ast50/se50000s.se1 +0 -0
- kerykeion/sweph/ast90/se90377s.se1 +0 -0
- kerykeion/sweph/ast90/se90482s.se1 +0 -0
- kerykeion/sweph/sefstars.txt +1602 -0
- kerykeion/transits_time_range_factory.py +302 -0
- kerykeion/utilities.py +626 -125
- kerykeion-5.1.9.dist-info/METADATA +1793 -0
- kerykeion-5.1.9.dist-info/RECORD +63 -0
- {kerykeion-4.18.3.dist-info → kerykeion-5.1.9.dist-info}/WHEEL +1 -1
- kerykeion/aspects/natal_aspects.py +0 -143
- kerykeion/aspects/synastry_aspects.py +0 -113
- kerykeion/astrological_subject.py +0 -818
- kerykeion/charts/kerykeion_chart_svg.py +0 -894
- kerykeion/enums.py +0 -51
- kerykeion/ephemeris_data.py +0 -178
- kerykeion/kr_types/chart_types.py +0 -88
- kerykeion/relationship_score/__init__.py +0 -2
- kerykeion/relationship_score/relationship_score.py +0 -175
- kerykeion/relationship_score/relationship_score_factory.py +0 -275
- kerykeion/settings/kr.config.json +0 -721
- kerykeion-4.18.3.dist-info/LICENSE +0 -661
- kerykeion-4.18.3.dist-info/METADATA +0 -396
- kerykeion-4.18.3.dist-info/RECORD +0 -42
- kerykeion-4.18.3.dist-info/entry_points.txt +0 -3
- /LICENSE → /kerykeion-5.1.9.dist-info/licenses/LICENSE +0 -0
|
@@ -0,0 +1,805 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
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
|
|
69
|
+
"""
|
|
70
|
+
import logging
|
|
71
|
+
import swisseph as swe
|
|
72
|
+
|
|
73
|
+
from datetime import datetime, timezone
|
|
74
|
+
from typing import Union
|
|
75
|
+
|
|
76
|
+
from kerykeion.schemas import KerykeionException
|
|
77
|
+
from kerykeion.fetch_geonames import FetchGeonames
|
|
78
|
+
from kerykeion.utilities import julian_to_datetime, datetime_to_julian
|
|
79
|
+
from kerykeion.astrological_subject_factory import (
|
|
80
|
+
GEONAMES_DEFAULT_USERNAME_WARNING,
|
|
81
|
+
DEFAULT_GEONAMES_CACHE_EXPIRE_AFTER_DAYS,
|
|
82
|
+
DEFAULT_GEONAMES_USERNAME,
|
|
83
|
+
)
|
|
84
|
+
from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
|
|
85
|
+
from kerykeion.schemas.kr_literals import ReturnType
|
|
86
|
+
from kerykeion.schemas.kr_models import PlanetReturnModel, AstrologicalSubjectModel
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class PlanetaryReturnFactory:
|
|
90
|
+
"""
|
|
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).
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
def __init__(
|
|
207
|
+
self,
|
|
208
|
+
subject: AstrologicalSubjectModel,
|
|
209
|
+
city: Union[str, None] = None,
|
|
210
|
+
nation: Union[str, None] = None,
|
|
211
|
+
lng: Union[int, float, None] = None,
|
|
212
|
+
lat: Union[int, float, None] = None,
|
|
213
|
+
tz_str: Union[str, None] = None,
|
|
214
|
+
online: bool = True,
|
|
215
|
+
geonames_username: Union[str, None] = None,
|
|
216
|
+
*,
|
|
217
|
+
cache_expire_after_days: int = DEFAULT_GEONAMES_CACHE_EXPIRE_AFTER_DAYS,
|
|
218
|
+
altitude: Union[float, int, None] = None,
|
|
219
|
+
):
|
|
220
|
+
|
|
221
|
+
"""
|
|
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.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
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
|
|
315
|
+
"""
|
|
316
|
+
# Store basic configuration
|
|
317
|
+
self.subject = subject
|
|
318
|
+
self.online = online
|
|
319
|
+
self.cache_expire_after_days = cache_expire_after_days
|
|
320
|
+
self.altitude = altitude
|
|
321
|
+
|
|
322
|
+
# Geonames username
|
|
323
|
+
if geonames_username is None and online and (not lat or not lng or not tz_str):
|
|
324
|
+
logging.warning(GEONAMES_DEFAULT_USERNAME_WARNING)
|
|
325
|
+
self.geonames_username = DEFAULT_GEONAMES_USERNAME
|
|
326
|
+
else:
|
|
327
|
+
self.geonames_username = geonames_username # type: ignore
|
|
328
|
+
|
|
329
|
+
# City
|
|
330
|
+
if not city and online:
|
|
331
|
+
raise KerykeionException("You need to set the city if you want to use the online mode!")
|
|
332
|
+
else:
|
|
333
|
+
self.city = city
|
|
334
|
+
|
|
335
|
+
# Nation
|
|
336
|
+
if not nation and online:
|
|
337
|
+
raise KerykeionException("You need to set the nation if you want to use the online mode!")
|
|
338
|
+
else:
|
|
339
|
+
self.nation = nation
|
|
340
|
+
|
|
341
|
+
# Latitude
|
|
342
|
+
if not lat and not online:
|
|
343
|
+
raise KerykeionException("You need to set the coordinates and timezone if you want to use the offline mode!")
|
|
344
|
+
else:
|
|
345
|
+
self.lat = lat # type: ignore
|
|
346
|
+
|
|
347
|
+
# Longitude
|
|
348
|
+
if not lng and not online:
|
|
349
|
+
raise KerykeionException("You need to set the coordinates and timezone if you want to use the offline mode!")
|
|
350
|
+
else:
|
|
351
|
+
self.lng = lng # type: ignore
|
|
352
|
+
|
|
353
|
+
# Timezone
|
|
354
|
+
if (not online) and (not tz_str):
|
|
355
|
+
raise KerykeionException("You need to set the coordinates and timezone if you want to use the offline mode!")
|
|
356
|
+
else:
|
|
357
|
+
self.tz_str = tz_str # type: ignore
|
|
358
|
+
|
|
359
|
+
# Online mode
|
|
360
|
+
if (self.online) and (not self.tz_str) and (not self.lat) and (not self.lng):
|
|
361
|
+
logging.info("Fetching timezone/coordinates from geonames")
|
|
362
|
+
|
|
363
|
+
if not self.city or not self.nation or not self.geonames_username:
|
|
364
|
+
raise KerykeionException("You need to set the city and nation if you want to use the online mode!")
|
|
365
|
+
|
|
366
|
+
geonames = FetchGeonames(
|
|
367
|
+
self.city,
|
|
368
|
+
self.nation,
|
|
369
|
+
username=self.geonames_username,
|
|
370
|
+
cache_expire_after_days=self.cache_expire_after_days
|
|
371
|
+
)
|
|
372
|
+
self.city_data: dict[str, str] = geonames.get_serialized_data()
|
|
373
|
+
|
|
374
|
+
if (
|
|
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
|
|
379
|
+
):
|
|
380
|
+
raise KerykeionException("No data found for this city, try again! Maybe check your connection?")
|
|
381
|
+
|
|
382
|
+
self.nation = self.city_data["countryCode"]
|
|
383
|
+
self.lng = float(self.city_data["lng"])
|
|
384
|
+
self.lat = float(self.city_data["lat"])
|
|
385
|
+
self.tz_str = self.city_data["timezonestr"]
|
|
386
|
+
|
|
387
|
+
def next_return_from_iso_formatted_time(
|
|
388
|
+
self,
|
|
389
|
+
iso_formatted_time: str,
|
|
390
|
+
return_type: ReturnType
|
|
391
|
+
) -> PlanetReturnModel:
|
|
392
|
+
"""
|
|
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
|
|
406
|
+
|
|
407
|
+
Args:
|
|
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.
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
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
|
|
482
|
+
"""
|
|
483
|
+
|
|
484
|
+
date = datetime.fromisoformat(iso_formatted_time)
|
|
485
|
+
julian_day = datetime_to_julian(date)
|
|
486
|
+
|
|
487
|
+
return_julian_date = None
|
|
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.")
|
|
491
|
+
return_julian_date = swe.solcross_ut(
|
|
492
|
+
self.subject.sun.abs_pos,
|
|
493
|
+
julian_day,
|
|
494
|
+
)
|
|
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.")
|
|
498
|
+
return_julian_date = swe.mooncross_ut(
|
|
499
|
+
self.subject.moon.abs_pos,
|
|
500
|
+
julian_day,
|
|
501
|
+
)
|
|
502
|
+
else:
|
|
503
|
+
raise KerykeionException(f"Invalid return type {return_type}. Use 'Solar' or 'Lunar'.")
|
|
504
|
+
|
|
505
|
+
solar_return_date_utc = julian_to_datetime(return_julian_date)
|
|
506
|
+
solar_return_date_utc = solar_return_date_utc.replace(tzinfo=timezone.utc)
|
|
507
|
+
|
|
508
|
+
solar_return_astrological_subject = AstrologicalSubjectFactory.from_iso_utc_time(
|
|
509
|
+
name=self.subject.name,
|
|
510
|
+
iso_utc_time=solar_return_date_utc.isoformat(),
|
|
511
|
+
lng=self.lng, # type: ignore
|
|
512
|
+
lat=self.lat, # type: ignore
|
|
513
|
+
tz_str=self.tz_str, # type: ignore
|
|
514
|
+
city=self.city, # type: ignore
|
|
515
|
+
nation=self.nation, # type: ignore
|
|
516
|
+
online=False,
|
|
517
|
+
altitude=self.altitude,
|
|
518
|
+
active_points=self.subject.active_points,
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
model_data = solar_return_astrological_subject.model_dump()
|
|
522
|
+
model_data['name'] = f"{self.subject.name} {return_type} Return"
|
|
523
|
+
model_data['return_type'] = return_type
|
|
524
|
+
|
|
525
|
+
return PlanetReturnModel(
|
|
526
|
+
**model_data,
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
def next_return_from_year(
|
|
530
|
+
self,
|
|
531
|
+
year: int,
|
|
532
|
+
return_type: ReturnType
|
|
533
|
+
) -> PlanetReturnModel:
|
|
534
|
+
"""
|
|
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.
|
|
541
|
+
|
|
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.
|
|
548
|
+
|
|
549
|
+
Args:
|
|
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.
|
|
555
|
+
|
|
556
|
+
Returns:
|
|
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
|
|
613
|
+
"""
|
|
614
|
+
# Create datetime for January 1st of the specified year (UTC)
|
|
615
|
+
start_date = datetime(year, 1, 1, 0, 0, tzinfo=timezone.utc)
|
|
616
|
+
|
|
617
|
+
# Get the return using the existing method
|
|
618
|
+
return self.next_return_from_iso_formatted_time(
|
|
619
|
+
start_date.isoformat(),
|
|
620
|
+
return_type
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
def next_return_from_month_and_year(
|
|
624
|
+
self,
|
|
625
|
+
year: int,
|
|
626
|
+
month: int,
|
|
627
|
+
return_type: ReturnType
|
|
628
|
+
) -> PlanetReturnModel:
|
|
629
|
+
"""
|
|
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.
|
|
636
|
+
|
|
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.
|
|
641
|
+
|
|
642
|
+
Args:
|
|
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.
|
|
650
|
+
|
|
651
|
+
Returns:
|
|
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
|
|
739
|
+
"""
|
|
740
|
+
# Validate month input
|
|
741
|
+
if month < 1 or month > 12:
|
|
742
|
+
raise KerykeionException(f"Invalid month {month}. Month must be between 1 and 12.")
|
|
743
|
+
|
|
744
|
+
# Create datetime for the first day of the specified month and year (UTC)
|
|
745
|
+
start_date = datetime(year, month, 1, 0, 0, tzinfo=timezone.utc)
|
|
746
|
+
|
|
747
|
+
# Get the return using the existing method
|
|
748
|
+
return self.next_return_from_iso_formatted_time(
|
|
749
|
+
start_date.isoformat(),
|
|
750
|
+
return_type
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
if __name__ == "__main__":
|
|
755
|
+
import json
|
|
756
|
+
# Example usage
|
|
757
|
+
subject = AstrologicalSubjectFactory.from_birth_data(
|
|
758
|
+
name="Test Subject",
|
|
759
|
+
lng=-122.4194,
|
|
760
|
+
lat=37.7749,
|
|
761
|
+
tz_str="America/Los_Angeles",
|
|
762
|
+
)
|
|
763
|
+
|
|
764
|
+
print("=== Planet Return Calculator ===")
|
|
765
|
+
calculator = PlanetaryReturnFactory(
|
|
766
|
+
subject,
|
|
767
|
+
city="San Francisco",
|
|
768
|
+
nation="USA",
|
|
769
|
+
online=True,
|
|
770
|
+
geonames_username="century.boy",
|
|
771
|
+
)
|
|
772
|
+
date = datetime(2026, 1, 1, 0, 0, tzinfo=timezone.utc)
|
|
773
|
+
print(f"INITIAL DATE: {date.isoformat()}")
|
|
774
|
+
print(f"INITIAL DATE JULIAN: {datetime_to_julian(date)}")
|
|
775
|
+
print(f"INITIAL DATE REVERSED: {julian_to_datetime(datetime_to_julian(date)).isoformat()}")
|
|
776
|
+
solar_return = calculator.next_return_from_iso_formatted_time(
|
|
777
|
+
date.isoformat(),
|
|
778
|
+
return_type="Lunar",
|
|
779
|
+
)
|
|
780
|
+
print("--- After ---")
|
|
781
|
+
print(f"Solar Return Date UTC: {solar_return.iso_formatted_utc_datetime}")
|
|
782
|
+
print(f"Solar Return Date Local: {solar_return.iso_formatted_local_datetime}")
|
|
783
|
+
print(f"Solar Return JSON: {json.dumps(solar_return.model_dump(), indent=4)}")
|
|
784
|
+
print(f"Solar Return Julian Data: {solar_return.julian_day}")
|
|
785
|
+
print(f"ISO UTC: {solar_return.iso_formatted_utc_datetime}")
|
|
786
|
+
|
|
787
|
+
## From Year
|
|
788
|
+
print("=== Planet Return Calculator ===")
|
|
789
|
+
solar_return = calculator.next_return_from_year(
|
|
790
|
+
2026,
|
|
791
|
+
return_type="Lunar",
|
|
792
|
+
)
|
|
793
|
+
print("--- From Year ---")
|
|
794
|
+
print(f"Solar Return Julian Data: {solar_return.julian_day}")
|
|
795
|
+
print(f"Solar Return Date UTC: {solar_return.iso_formatted_utc_datetime}")
|
|
796
|
+
## From Month and Year
|
|
797
|
+
print("=== Planet Return Calculator ===")
|
|
798
|
+
solar_return = calculator.next_return_from_month_and_year(
|
|
799
|
+
2026,
|
|
800
|
+
1,
|
|
801
|
+
return_type="Lunar",
|
|
802
|
+
)
|
|
803
|
+
print("--- From Month and Year ---")
|
|
804
|
+
print(f"Solar Return Julian Data: {solar_return.julian_day}")
|
|
805
|
+
print(f"Solar Return Date UTC: {solar_return.iso_formatted_utc_datetime}")
|