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.
- kerykeion/__init__.py +4 -9
- kerykeion/aspects/__init__.py +2 -4
- kerykeion/aspects/aspects_factory.py +514 -0
- kerykeion/astrological_subject_factory.py +685 -79
- kerykeion/charts/draw_planets.py +584 -343
- kerykeion/charts/kerykeion_chart_svg.py +10 -16
- kerykeion/charts/templates/wheel_only.xml +1 -1
- kerykeion/composite_subject_factory.py +228 -9
- kerykeion/ephemeris_data_factory.py +431 -0
- kerykeion/fetch_geonames.py +27 -8
- kerykeion/house_comparison/house_comparison_factory.py +48 -15
- kerykeion/house_comparison/house_comparison_models.py +51 -13
- kerykeion/house_comparison/house_comparison_utils.py +35 -5
- kerykeion/kr_types/kerykeion_exception.py +6 -0
- kerykeion/kr_types/kr_models.py +82 -12
- kerykeion/planetary_return_factory.py +532 -32
- kerykeion/relationship_score_factory.py +98 -44
- kerykeion/report.py +7 -0
- kerykeion/sweph/sefstars.txt +1602 -0
- kerykeion/transits_time_range_factory.py +293 -0
- kerykeion/utilities.py +129 -67
- {kerykeion-5.0.0a10.dist-info → kerykeion-5.0.0a12.dist-info}/METADATA +49 -22
- kerykeion-5.0.0a12.dist-info/RECORD +50 -0
- kerykeion/aspects/natal_aspects_factory.py +0 -236
- kerykeion/aspects/synastry_aspects_factory.py +0 -234
- kerykeion/charts/draw_planets_v2.py +0 -648
- kerykeion/charts/draw_planets_v3.py +0 -679
- kerykeion/enums.py +0 -57
- kerykeion/ephemeris_data.py +0 -238
- kerykeion/transits_time_range.py +0 -128
- kerykeion-5.0.0a10.dist-info/RECORD +0 -53
- {kerykeion-5.0.0a10.dist-info → kerykeion-5.0.0a12.dist-info}/WHEEL +0 -0
- {kerykeion-5.0.0a10.dist-info → kerykeion-5.0.0a12.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""
|
|
3
|
-
|
|
3
|
+
Astrological Subject Factory Module
|
|
4
|
+
|
|
5
|
+
This module provides factory classes for creating astrological subjects with comprehensive
|
|
6
|
+
astrological calculations including planetary positions, house cusps, aspects, and various
|
|
7
|
+
astrological points.
|
|
8
|
+
|
|
9
|
+
The main factory class AstrologicalSubjectFactory offers multiple creation methods for
|
|
10
|
+
different initialization scenarios, supporting both online and offline calculation modes,
|
|
11
|
+
various zodiac systems (Tropical/Sidereal), house systems, and coordinate perspectives.
|
|
12
|
+
|
|
13
|
+
Key Features:
|
|
14
|
+
- Planetary position calculations for all traditional and modern planets
|
|
15
|
+
- House cusp calculations with multiple house systems
|
|
16
|
+
- Lunar nodes, Lilith points, asteroids, and trans-Neptunian objects
|
|
17
|
+
- Arabic parts (lots) calculations
|
|
18
|
+
- Fixed star positions
|
|
19
|
+
- Automatic location data fetching via GeoNames API
|
|
20
|
+
- Comprehensive timezone and coordinate handling
|
|
21
|
+
- Flexible point selection for performance optimization
|
|
22
|
+
|
|
23
|
+
Classes:
|
|
24
|
+
ChartConfiguration: Configuration settings for astrological calculations
|
|
25
|
+
LocationData: Geographical location information and utilities
|
|
26
|
+
AstrologicalSubjectFactory: Main factory for creating astrological subjects
|
|
27
|
+
|
|
28
|
+
Author: Giacomo Battaglia
|
|
29
|
+
Copyright: (C) 2025 Kerykeion Project
|
|
30
|
+
License: AGPL-3.0
|
|
4
31
|
"""
|
|
5
32
|
|
|
6
33
|
import pytz
|
|
@@ -59,14 +86,62 @@ NOW = datetime.now()
|
|
|
59
86
|
|
|
60
87
|
@dataclass
|
|
61
88
|
class ChartConfiguration:
|
|
62
|
-
"""
|
|
89
|
+
"""
|
|
90
|
+
Configuration settings for astrological chart calculations.
|
|
91
|
+
|
|
92
|
+
This class encapsulates all the configuration parameters needed for astrological
|
|
93
|
+
calculations, including zodiac type, coordinate systems, house systems, and
|
|
94
|
+
calculation perspectives. It provides validation to ensure compatible settings
|
|
95
|
+
combinations.
|
|
96
|
+
|
|
97
|
+
Attributes:
|
|
98
|
+
zodiac_type (ZodiacType): The zodiac system to use ('Tropic' or 'Sidereal').
|
|
99
|
+
Defaults to 'Tropic'.
|
|
100
|
+
sidereal_mode (Optional[SiderealMode]): The sidereal calculation mode when using
|
|
101
|
+
sidereal zodiac. Only required/used when zodiac_type is 'Sidereal'.
|
|
102
|
+
Defaults to None (auto-set to FAGAN_BRADLEY for sidereal).
|
|
103
|
+
houses_system_identifier (HousesSystemIdentifier): The house system to use for
|
|
104
|
+
house cusp calculations. Defaults to 'P' (Placidus).
|
|
105
|
+
perspective_type (PerspectiveType): The coordinate perspective for calculations.
|
|
106
|
+
Options include 'Apparent Geocentric', 'True Geocentric', 'Heliocentric',
|
|
107
|
+
or 'Topocentric'. Defaults to 'Apparent Geocentric'.
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
KerykeionException: When invalid configuration combinations are detected,
|
|
111
|
+
such as setting sidereal_mode with tropical zodiac, or using invalid
|
|
112
|
+
enumeration values.
|
|
113
|
+
|
|
114
|
+
Example:
|
|
115
|
+
>>> config = ChartConfiguration(
|
|
116
|
+
... zodiac_type="Sidereal",
|
|
117
|
+
... sidereal_mode="LAHIRI",
|
|
118
|
+
... houses_system_identifier="K",
|
|
119
|
+
... perspective_type="Topocentric"
|
|
120
|
+
... )
|
|
121
|
+
>>> config.validate()
|
|
122
|
+
"""
|
|
63
123
|
zodiac_type: ZodiacType = DEFAULT_ZODIAC_TYPE
|
|
64
124
|
sidereal_mode: Optional[SiderealMode] = None
|
|
65
125
|
houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER
|
|
66
126
|
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE
|
|
67
127
|
|
|
68
128
|
def validate(self) -> None:
|
|
69
|
-
"""
|
|
129
|
+
"""
|
|
130
|
+
Validate configuration settings for internal consistency.
|
|
131
|
+
|
|
132
|
+
Performs comprehensive validation of all configuration parameters to ensure
|
|
133
|
+
they form a valid, compatible combination. This includes checking enumeration
|
|
134
|
+
values, zodiac/sidereal mode compatibility, and setting defaults where needed.
|
|
135
|
+
|
|
136
|
+
Raises:
|
|
137
|
+
KerykeionException: If any configuration parameter is invalid or if
|
|
138
|
+
incompatible parameter combinations are detected.
|
|
139
|
+
|
|
140
|
+
Side Effects:
|
|
141
|
+
- Sets default sidereal_mode to FAGAN_BRADLEY if zodiac_type is Sidereal
|
|
142
|
+
and no sidereal_mode is specified
|
|
143
|
+
- Logs informational message when setting default sidereal mode
|
|
144
|
+
"""
|
|
70
145
|
# Validate zodiac type
|
|
71
146
|
if self.zodiac_type not in get_args(ZodiacType):
|
|
72
147
|
raise KerykeionException(
|
|
@@ -101,7 +176,39 @@ class ChartConfiguration:
|
|
|
101
176
|
|
|
102
177
|
@dataclass
|
|
103
178
|
class LocationData:
|
|
104
|
-
"""
|
|
179
|
+
"""
|
|
180
|
+
Information about a geographical location for astrological calculations.
|
|
181
|
+
|
|
182
|
+
This class handles all location-related data including coordinates, timezone
|
|
183
|
+
information, and interaction with the GeoNames API for automatic location
|
|
184
|
+
data retrieval. It provides methods for fetching location data online and
|
|
185
|
+
preparing coordinates for astrological calculations.
|
|
186
|
+
|
|
187
|
+
Attributes:
|
|
188
|
+
city (str): Name of the city or location. Defaults to "Greenwich".
|
|
189
|
+
nation (str): ISO country code (2-letter). Defaults to "GB" (United Kingdom).
|
|
190
|
+
lat (float): Latitude in decimal degrees. Positive for North, negative for South.
|
|
191
|
+
Defaults to 51.5074 (Greenwich).
|
|
192
|
+
lng (float): Longitude in decimal degrees. Positive for East, negative for West.
|
|
193
|
+
Defaults to 0.0 (Greenwich).
|
|
194
|
+
tz_str (str): IANA timezone identifier (e.g., 'Europe/London', 'America/New_York').
|
|
195
|
+
Defaults to "Etc/GMT".
|
|
196
|
+
altitude (Optional[float]): Altitude above sea level in meters. Used for
|
|
197
|
+
topocentric calculations. Defaults to None (sea level assumed).
|
|
198
|
+
city_data (Dict[str, str]): Raw data retrieved from GeoNames API. Used internally
|
|
199
|
+
for caching and validation. Defaults to empty dictionary.
|
|
200
|
+
|
|
201
|
+
Note:
|
|
202
|
+
When using online mode, the initial coordinate and timezone values may be
|
|
203
|
+
overridden by data fetched from the GeoNames API based on city and nation.
|
|
204
|
+
For polar regions, latitude values are automatically adjusted to prevent
|
|
205
|
+
calculation errors.
|
|
206
|
+
|
|
207
|
+
Example:
|
|
208
|
+
>>> location = LocationData(city="Rome", nation="IT")
|
|
209
|
+
>>> location.fetch_from_geonames("your_username", 30)
|
|
210
|
+
>>> location.prepare_for_calculation()
|
|
211
|
+
"""
|
|
105
212
|
city: str = "Greenwich"
|
|
106
213
|
nation: str = "GB"
|
|
107
214
|
lat: float = 51.5074
|
|
@@ -113,7 +220,32 @@ class LocationData:
|
|
|
113
220
|
city_data: Dict[str, str] = field(default_factory=dict)
|
|
114
221
|
|
|
115
222
|
def fetch_from_geonames(self, username: str, cache_expire_after_days: int) -> None:
|
|
116
|
-
"""
|
|
223
|
+
"""
|
|
224
|
+
Fetch location data from GeoNames API.
|
|
225
|
+
|
|
226
|
+
Retrieves accurate coordinates, timezone, and country code information
|
|
227
|
+
for the specified city and country from the GeoNames web service.
|
|
228
|
+
Updates the instance attributes with the fetched data.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
username (str): GeoNames API username. Must be registered at geonames.org.
|
|
232
|
+
Free accounts are limited to 2000 requests per hour.
|
|
233
|
+
cache_expire_after_days (int): Number of days to cache the location data
|
|
234
|
+
locally before refreshing from the API.
|
|
235
|
+
|
|
236
|
+
Raises:
|
|
237
|
+
KerykeionException: If required data is missing from the API response,
|
|
238
|
+
typically due to network issues, invalid location names, or API limits.
|
|
239
|
+
|
|
240
|
+
Side Effects:
|
|
241
|
+
- Updates city_data with raw API response
|
|
242
|
+
- Updates nation, lng, lat, and tz_str with fetched values
|
|
243
|
+
- May create or update local cache files
|
|
244
|
+
|
|
245
|
+
Note:
|
|
246
|
+
The method validates that all required fields (countryCode, timezonestr,
|
|
247
|
+
lat, lng) are present in the API response before updating instance attributes.
|
|
248
|
+
"""
|
|
117
249
|
logging.info(f"Fetching timezone/coordinates for {self.city}, {self.nation} from geonames")
|
|
118
250
|
|
|
119
251
|
geonames = FetchGeonames(
|
|
@@ -142,18 +274,90 @@ class LocationData:
|
|
|
142
274
|
self.tz_str = self.city_data["timezonestr"]
|
|
143
275
|
|
|
144
276
|
def prepare_for_calculation(self) -> None:
|
|
145
|
-
"""
|
|
277
|
+
"""
|
|
278
|
+
Prepare location data for astrological calculations.
|
|
279
|
+
|
|
280
|
+
Performs final adjustments to location data to ensure compatibility
|
|
281
|
+
with Swiss Ephemeris calculations. This includes handling special cases
|
|
282
|
+
like polar regions where extreme latitudes can cause calculation errors.
|
|
283
|
+
|
|
284
|
+
Side Effects:
|
|
285
|
+
- Adjusts latitude values for polar regions (beyond ±66.5°) to
|
|
286
|
+
prevent Swiss Ephemeris calculation failures
|
|
287
|
+
- May log warnings about latitude adjustments
|
|
288
|
+
|
|
289
|
+
Note:
|
|
290
|
+
This method should be called after all location data has been set,
|
|
291
|
+
either manually or via fetch_from_geonames(), and before performing
|
|
292
|
+
any astrological calculations.
|
|
293
|
+
"""
|
|
146
294
|
# Adjust latitude for polar regions
|
|
147
295
|
self.lat = check_and_adjust_polar_latitude(self.lat)
|
|
148
296
|
|
|
149
297
|
|
|
150
298
|
class AstrologicalSubjectFactory:
|
|
151
299
|
"""
|
|
152
|
-
Factory class for creating astrological subjects
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
multiple
|
|
300
|
+
Factory class for creating comprehensive astrological subjects.
|
|
301
|
+
|
|
302
|
+
This factory creates AstrologicalSubjectModel instances with complete astrological
|
|
303
|
+
information including planetary positions, house cusps, aspects, lunar phases, and
|
|
304
|
+
various specialized astrological points. It provides multiple class methods for
|
|
305
|
+
different initialization scenarios and supports both online and offline calculation modes.
|
|
306
|
+
|
|
307
|
+
The factory handles complex astrological calculations using the Swiss Ephemeris library,
|
|
308
|
+
supports multiple coordinate systems and house systems, and can automatically fetch
|
|
309
|
+
location data from online sources.
|
|
310
|
+
|
|
311
|
+
Supported Astrological Points:
|
|
312
|
+
- Traditional Planets: Sun through Pluto
|
|
313
|
+
- Lunar Nodes: Mean and True North/South Nodes
|
|
314
|
+
- Lilith Points: Mean and True Black Moon
|
|
315
|
+
- Asteroids: Ceres, Pallas, Juno, Vesta
|
|
316
|
+
- Centaurs: Chiron, Pholus
|
|
317
|
+
- Trans-Neptunian Objects: Eris, Sedna, Haumea, Makemake, Ixion, Orcus, Quaoar
|
|
318
|
+
- Fixed Stars: Regulus, Spica (extensible)
|
|
319
|
+
- Arabic Parts: Pars Fortunae, Pars Spiritus, Pars Amoris, Pars Fidei
|
|
320
|
+
- Special Points: Vertex, Anti-Vertex, Earth (for heliocentric charts)
|
|
321
|
+
- House Cusps: All 12 houses with configurable house systems
|
|
322
|
+
- Angles: Ascendant, Medium Coeli, Descendant, Imum Coeli
|
|
323
|
+
|
|
324
|
+
Supported Features:
|
|
325
|
+
- Multiple zodiac systems (Tropical/Sidereal with various ayanamshas)
|
|
326
|
+
- Multiple house systems (Placidus, Koch, Equal, Whole Sign, etc.)
|
|
327
|
+
- Multiple coordinate perspectives (Geocentric, Heliocentric, Topocentric)
|
|
328
|
+
- Automatic timezone and coordinate resolution via GeoNames API
|
|
329
|
+
- Lunar phase calculations
|
|
330
|
+
- Day/night chart detection for Arabic parts
|
|
331
|
+
- Performance optimization through selective point calculation
|
|
332
|
+
- Comprehensive error handling and validation
|
|
333
|
+
|
|
334
|
+
Class Methods:
|
|
335
|
+
from_birth_data: Create subject from standard birth data (most flexible)
|
|
336
|
+
from_iso_utc_time: Create subject from ISO UTC timestamp
|
|
337
|
+
from_current_time: Create subject for current moment
|
|
338
|
+
|
|
339
|
+
Example:
|
|
340
|
+
>>> # Create natal chart
|
|
341
|
+
>>> subject = AstrologicalSubjectFactory.from_birth_data(
|
|
342
|
+
... name="John Doe",
|
|
343
|
+
... year=1990, month=6, day=15,
|
|
344
|
+
... hour=14, minute=30,
|
|
345
|
+
... city="Rome", nation="IT",
|
|
346
|
+
... online=True
|
|
347
|
+
... )
|
|
348
|
+
>>> print(f"Sun: {subject.sun.sign} {subject.sun.abs_pos}°")
|
|
349
|
+
>>> print(f"Active points: {len(subject.active_points)}")
|
|
350
|
+
|
|
351
|
+
>>> # Create chart for current time
|
|
352
|
+
>>> now_subject = AstrologicalSubjectFactory.from_current_time(
|
|
353
|
+
... name="Current Moment",
|
|
354
|
+
... city="London", nation="GB"
|
|
355
|
+
... )
|
|
356
|
+
|
|
357
|
+
Thread Safety:
|
|
358
|
+
This factory is not thread-safe due to its use of the Swiss Ephemeris library
|
|
359
|
+
which maintains global state. Use separate instances in multi-threaded applications
|
|
360
|
+
or implement appropriate locking mechanisms.
|
|
157
361
|
"""
|
|
158
362
|
|
|
159
363
|
@classmethod
|
|
@@ -186,29 +390,110 @@ class AstrologicalSubjectFactory:
|
|
|
186
390
|
|
|
187
391
|
) -> AstrologicalSubjectModel:
|
|
188
392
|
"""
|
|
189
|
-
Create an astrological subject from standard birth
|
|
393
|
+
Create an astrological subject from standard birth or event data.
|
|
394
|
+
|
|
395
|
+
This is the most flexible and commonly used factory method. It creates a complete
|
|
396
|
+
astrological subject with planetary positions, house cusps, and specialized points
|
|
397
|
+
for a specific date, time, and location. Supports both online location resolution
|
|
398
|
+
and offline calculation modes.
|
|
190
399
|
|
|
191
400
|
Args:
|
|
192
|
-
name:
|
|
193
|
-
year
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
401
|
+
name (str, optional): Name or identifier for the subject. Defaults to "Now".
|
|
402
|
+
year (int, optional): Year of birth/event. Defaults to current year.
|
|
403
|
+
month (int, optional): Month of birth/event (1-12). Defaults to current month.
|
|
404
|
+
day (int, optional): Day of birth/event (1-31). Defaults to current day.
|
|
405
|
+
hour (int, optional): Hour of birth/event (0-23). Defaults to current hour.
|
|
406
|
+
minute (int, optional): Minute of birth/event (0-59). Defaults to current minute.
|
|
407
|
+
seconds (int, optional): Seconds of birth/event (0-59). Defaults to 0.
|
|
408
|
+
city (str, optional): City name for location lookup. Used with online=True.
|
|
409
|
+
Defaults to None (Greenwich if not specified).
|
|
410
|
+
nation (str, optional): ISO country code (e.g., 'US', 'GB', 'IT'). Used with
|
|
411
|
+
online=True. Defaults to None ('GB' if not specified).
|
|
412
|
+
lng (float, optional): Longitude in decimal degrees. East is positive, West
|
|
413
|
+
is negative. If not provided and online=True, fetched from GeoNames.
|
|
414
|
+
lat (float, optional): Latitude in decimal degrees. North is positive, South
|
|
415
|
+
is negative. If not provided and online=True, fetched from GeoNames.
|
|
416
|
+
tz_str (str, optional): IANA timezone identifier (e.g., 'Europe/London').
|
|
417
|
+
If not provided and online=True, fetched from GeoNames.
|
|
418
|
+
geonames_username (str, optional): Username for GeoNames API. Required for
|
|
419
|
+
online location lookup. Get one free at geonames.org.
|
|
420
|
+
online (bool, optional): Whether to fetch location data online. If False,
|
|
421
|
+
lng, lat, and tz_str must be provided. Defaults to True.
|
|
422
|
+
zodiac_type (ZodiacType, optional): Zodiac system - 'Tropic' or 'Sidereal'.
|
|
423
|
+
Defaults to 'Tropic'.
|
|
424
|
+
sidereal_mode (SiderealMode, optional): Sidereal calculation mode (e.g.,
|
|
425
|
+
'FAGAN_BRADLEY', 'LAHIRI'). Only used with zodiac_type='Sidereal'.
|
|
426
|
+
houses_system_identifier (HousesSystemIdentifier, optional): House system
|
|
427
|
+
for cusp calculations (e.g., 'P'=Placidus, 'K'=Koch, 'E'=Equal).
|
|
428
|
+
Defaults to 'P' (Placidus).
|
|
429
|
+
perspective_type (PerspectiveType, optional): Calculation perspective:
|
|
430
|
+
- 'Apparent Geocentric': Standard geocentric with light-time correction
|
|
431
|
+
- 'True Geocentric': Geometric geocentric positions
|
|
432
|
+
- 'Heliocentric': Sun-centered coordinates
|
|
433
|
+
- 'Topocentric': Earth surface perspective (requires altitude)
|
|
434
|
+
Defaults to 'Apparent Geocentric'.
|
|
435
|
+
cache_expire_after_days (int, optional): Days to cache GeoNames data locally.
|
|
436
|
+
Defaults to 30.
|
|
437
|
+
is_dst (bool, optional): Daylight Saving Time flag for ambiguous times.
|
|
438
|
+
If None, pytz attempts automatic detection. Set explicitly for
|
|
439
|
+
times during DST transitions.
|
|
440
|
+
altitude (float, optional): Altitude above sea level in meters. Used for
|
|
441
|
+
topocentric calculations and atmospheric corrections. Defaults to None
|
|
442
|
+
(sea level assumed).
|
|
443
|
+
active_points (List[AstrologicalPoint], optional): List of astrological
|
|
444
|
+
points to calculate. Omitting points can improve performance for
|
|
445
|
+
specialized applications. Defaults to DEFAULT_ACTIVE_POINTS.
|
|
446
|
+
calculate_lunar_phase (bool, optional): Whether to calculate lunar phase.
|
|
447
|
+
Requires Sun and Moon in active_points. Defaults to True.
|
|
209
448
|
|
|
210
449
|
Returns:
|
|
211
|
-
|
|
450
|
+
AstrologicalSubjectModel: Complete astrological subject with calculated
|
|
451
|
+
positions, houses, and metadata. Access planetary positions via
|
|
452
|
+
attributes like .sun, .moon, .mercury, etc.
|
|
453
|
+
|
|
454
|
+
Raises:
|
|
455
|
+
KerykeionException:
|
|
456
|
+
- If offline mode is used without required location data
|
|
457
|
+
- If invalid zodiac/sidereal mode combinations are specified
|
|
458
|
+
- If GeoNames data is missing or invalid
|
|
459
|
+
- If timezone localization fails (ambiguous DST times)
|
|
460
|
+
|
|
461
|
+
Examples:
|
|
462
|
+
>>> # Basic natal chart with online location lookup
|
|
463
|
+
>>> chart = AstrologicalSubjectFactory.from_birth_data(
|
|
464
|
+
... name="Jane Doe",
|
|
465
|
+
... year=1985, month=3, day=21,
|
|
466
|
+
... hour=15, minute=30,
|
|
467
|
+
... city="Paris", nation="FR",
|
|
468
|
+
... geonames_username="your_username"
|
|
469
|
+
... )
|
|
470
|
+
|
|
471
|
+
>>> # Offline calculation with manual coordinates
|
|
472
|
+
>>> chart = AstrologicalSubjectFactory.from_birth_data(
|
|
473
|
+
... name="John Smith",
|
|
474
|
+
... year=1990, month=12, day=25,
|
|
475
|
+
... hour=0, minute=0,
|
|
476
|
+
... lng=-74.006, lat=40.7128, tz_str="America/New_York",
|
|
477
|
+
... online=False
|
|
478
|
+
... )
|
|
479
|
+
|
|
480
|
+
>>> # Sidereal chart with specific points
|
|
481
|
+
>>> chart = AstrologicalSubjectFactory.from_birth_data(
|
|
482
|
+
... name="Vedic Chart",
|
|
483
|
+
... year=2000, month=6, day=15, hour=12,
|
|
484
|
+
... city="Mumbai", nation="IN",
|
|
485
|
+
... zodiac_type="Sidereal",
|
|
486
|
+
... sidereal_mode="LAHIRI",
|
|
487
|
+
... active_points=["Sun", "Moon", "Mercury", "Venus", "Mars",
|
|
488
|
+
... "Jupiter", "Saturn", "Ascendant"]
|
|
489
|
+
... )
|
|
490
|
+
|
|
491
|
+
Note:
|
|
492
|
+
- For high-precision calculations, consider providing seconds parameter
|
|
493
|
+
- Use topocentric perspective for observer-specific calculations
|
|
494
|
+
- Some Arabic parts automatically activate required base points
|
|
495
|
+
- The method handles polar regions by adjusting extreme latitudes
|
|
496
|
+
- Time zones are handled with full DST awareness via pytz
|
|
212
497
|
"""
|
|
213
498
|
# Create a calculation data container
|
|
214
499
|
calc_data = {}
|
|
@@ -325,27 +610,78 @@ class AstrologicalSubjectFactory:
|
|
|
325
610
|
calculate_lunar_phase: bool = True
|
|
326
611
|
) -> AstrologicalSubjectModel:
|
|
327
612
|
"""
|
|
328
|
-
Create an astrological subject from an ISO formatted UTC
|
|
613
|
+
Create an astrological subject from an ISO formatted UTC timestamp.
|
|
614
|
+
|
|
615
|
+
This method is ideal for creating astrological subjects from standardized
|
|
616
|
+
time formats, such as those stored in databases or received from APIs.
|
|
617
|
+
It automatically handles timezone conversion from UTC to the specified
|
|
618
|
+
local timezone.
|
|
329
619
|
|
|
330
620
|
Args:
|
|
331
|
-
name:
|
|
332
|
-
iso_utc_time: ISO formatted UTC
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
621
|
+
name (str): Name or identifier for the subject.
|
|
622
|
+
iso_utc_time (str): ISO 8601 formatted UTC timestamp. Supported formats:
|
|
623
|
+
- "2023-06-15T14:30:00Z" (with Z suffix)
|
|
624
|
+
- "2023-06-15T14:30:00+00:00" (with UTC offset)
|
|
625
|
+
- "2023-06-15T14:30:00.123Z" (with milliseconds)
|
|
626
|
+
city (str, optional): City name for location. Defaults to "Greenwich".
|
|
627
|
+
nation (str, optional): ISO country code. Defaults to "GB".
|
|
628
|
+
tz_str (str, optional): IANA timezone identifier for result conversion.
|
|
629
|
+
The ISO time is assumed to be in UTC and will be converted to this
|
|
630
|
+
timezone. Defaults to "Etc/GMT".
|
|
631
|
+
online (bool, optional): Whether to fetch coordinates online. If True,
|
|
632
|
+
coordinates are fetched via GeoNames API. Defaults to True.
|
|
633
|
+
lng (float, optional): Longitude in decimal degrees. Used when online=False
|
|
634
|
+
or as fallback. Defaults to 0.0 (Greenwich).
|
|
635
|
+
lat (float, optional): Latitude in decimal degrees. Used when online=False
|
|
636
|
+
or as fallback. Defaults to 51.5074 (Greenwich).
|
|
637
|
+
geonames_username (str, optional): GeoNames API username. Required when
|
|
638
|
+
online=True. Defaults to DEFAULT_GEONAMES_USERNAME.
|
|
639
|
+
zodiac_type (ZodiacType, optional): Zodiac system. Defaults to 'Tropic'.
|
|
640
|
+
sidereal_mode (SiderealMode, optional): Sidereal mode when zodiac_type
|
|
641
|
+
is 'Sidereal'. Defaults to None.
|
|
642
|
+
houses_system_identifier (HousesSystemIdentifier, optional): House system.
|
|
643
|
+
Defaults to 'P' (Placidus).
|
|
644
|
+
perspective_type (PerspectiveType, optional): Calculation perspective.
|
|
645
|
+
Defaults to 'Apparent Geocentric'.
|
|
646
|
+
altitude (float, optional): Altitude in meters for topocentric calculations.
|
|
647
|
+
Defaults to None (sea level).
|
|
648
|
+
active_points (List[AstrologicalPoint], optional): Points to calculate.
|
|
649
|
+
Defaults to DEFAULT_ACTIVE_POINTS.
|
|
650
|
+
calculate_lunar_phase (bool, optional): Whether to calculate lunar phase.
|
|
651
|
+
Defaults to True.
|
|
346
652
|
|
|
347
653
|
Returns:
|
|
348
|
-
AstrologicalSubjectModel
|
|
654
|
+
AstrologicalSubjectModel: Astrological subject with positions calculated
|
|
655
|
+
for the specified UTC time converted to local timezone.
|
|
656
|
+
|
|
657
|
+
Raises:
|
|
658
|
+
ValueError: If the ISO timestamp format is invalid or cannot be parsed.
|
|
659
|
+
KerykeionException: If location data cannot be fetched or is invalid.
|
|
660
|
+
|
|
661
|
+
Examples:
|
|
662
|
+
>>> # From API timestamp with online location lookup
|
|
663
|
+
>>> subject = AstrologicalSubjectFactory.from_iso_utc_time(
|
|
664
|
+
... name="Event Chart",
|
|
665
|
+
... iso_utc_time="2023-12-25T12:00:00Z",
|
|
666
|
+
... city="Tokyo", nation="JP",
|
|
667
|
+
... tz_str="Asia/Tokyo",
|
|
668
|
+
... geonames_username="your_username"
|
|
669
|
+
... )
|
|
670
|
+
|
|
671
|
+
>>> # From database timestamp with manual coordinates
|
|
672
|
+
>>> subject = AstrologicalSubjectFactory.from_iso_utc_time(
|
|
673
|
+
... name="Historical Event",
|
|
674
|
+
... iso_utc_time="1969-07-20T20:17:00Z",
|
|
675
|
+
... lng=-95.0969, lat=37.4419, # Houston
|
|
676
|
+
... tz_str="America/Chicago",
|
|
677
|
+
... online=False
|
|
678
|
+
... )
|
|
679
|
+
|
|
680
|
+
Note:
|
|
681
|
+
- The method assumes the input timestamp is in UTC
|
|
682
|
+
- Local time conversion respects DST rules for the target timezone
|
|
683
|
+
- Milliseconds in the timestamp are supported but truncated to seconds
|
|
684
|
+
- When online=True, the city/nation parameters override lng/lat
|
|
349
685
|
"""
|
|
350
686
|
# Parse the ISO time
|
|
351
687
|
dt = datetime.fromisoformat(iso_utc_time.replace('Z', '+00:00'))
|
|
@@ -413,25 +749,79 @@ class AstrologicalSubjectFactory:
|
|
|
413
749
|
calculate_lunar_phase: bool = True
|
|
414
750
|
) -> AstrologicalSubjectModel:
|
|
415
751
|
"""
|
|
416
|
-
Create an astrological subject for the current time.
|
|
752
|
+
Create an astrological subject for the current moment in time.
|
|
753
|
+
|
|
754
|
+
This convenience method creates a "now" chart, capturing the current
|
|
755
|
+
astrological conditions at the moment of execution. Useful for horary
|
|
756
|
+
astrology, electional astrology, or real-time astrological monitoring.
|
|
417
757
|
|
|
418
758
|
Args:
|
|
419
|
-
name:
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
759
|
+
name (str, optional): Name for the current moment chart.
|
|
760
|
+
Defaults to "Now".
|
|
761
|
+
city (str, optional): City name for location lookup. If not provided
|
|
762
|
+
and online=True, defaults to Greenwich.
|
|
763
|
+
nation (str, optional): ISO country code. If not provided and
|
|
764
|
+
online=True, defaults to 'GB'.
|
|
765
|
+
lng (float, optional): Longitude in decimal degrees. If not provided
|
|
766
|
+
and online=True, fetched from GeoNames API.
|
|
767
|
+
lat (float, optional): Latitude in decimal degrees. If not provided
|
|
768
|
+
and online=True, fetched from GeoNames API.
|
|
769
|
+
tz_str (str, optional): IANA timezone identifier. If not provided
|
|
770
|
+
and online=True, fetched from GeoNames API.
|
|
771
|
+
geonames_username (str, optional): GeoNames API username for location
|
|
772
|
+
lookup. Required when online=True and location is not fully specified.
|
|
773
|
+
online (bool, optional): Whether to fetch location data online.
|
|
774
|
+
Defaults to True.
|
|
775
|
+
zodiac_type (ZodiacType, optional): Zodiac system to use.
|
|
776
|
+
Defaults to 'Tropic'.
|
|
777
|
+
sidereal_mode (SiderealMode, optional): Sidereal calculation mode.
|
|
778
|
+
Only used when zodiac_type is 'Sidereal'. Defaults to None.
|
|
779
|
+
houses_system_identifier (HousesSystemIdentifier, optional): House
|
|
780
|
+
system for calculations. Defaults to 'P' (Placidus).
|
|
781
|
+
perspective_type (PerspectiveType, optional): Calculation perspective.
|
|
782
|
+
Defaults to 'Apparent Geocentric'.
|
|
783
|
+
active_points (List[AstrologicalPoint], optional): Astrological points
|
|
784
|
+
to calculate. Defaults to DEFAULT_ACTIVE_POINTS.
|
|
785
|
+
calculate_lunar_phase (bool, optional): Whether to calculate lunar phase.
|
|
786
|
+
Defaults to True.
|
|
432
787
|
|
|
433
788
|
Returns:
|
|
434
|
-
AstrologicalSubjectModel
|
|
789
|
+
AstrologicalSubjectModel: Astrological subject representing current
|
|
790
|
+
astrological conditions at the specified or default location.
|
|
791
|
+
|
|
792
|
+
Raises:
|
|
793
|
+
KerykeionException: If online location lookup fails or if offline mode
|
|
794
|
+
is used without sufficient location data.
|
|
795
|
+
|
|
796
|
+
Examples:
|
|
797
|
+
>>> # Current moment for your location
|
|
798
|
+
>>> now_chart = AstrologicalSubjectFactory.from_current_time(
|
|
799
|
+
... name="Current Transits",
|
|
800
|
+
... city="New York", nation="US",
|
|
801
|
+
... geonames_username="your_username"
|
|
802
|
+
... )
|
|
803
|
+
|
|
804
|
+
>>> # Horary chart with specific coordinates
|
|
805
|
+
>>> horary = AstrologicalSubjectFactory.from_current_time(
|
|
806
|
+
... name="Horary Question",
|
|
807
|
+
... lng=-0.1278, lat=51.5074, # London
|
|
808
|
+
... tz_str="Europe/London",
|
|
809
|
+
... online=False
|
|
810
|
+
... )
|
|
811
|
+
|
|
812
|
+
>>> # Current sidereal positions
|
|
813
|
+
>>> sidereal_now = AstrologicalSubjectFactory.from_current_time(
|
|
814
|
+
... name="Sidereal Now",
|
|
815
|
+
... city="Mumbai", nation="IN",
|
|
816
|
+
... zodiac_type="Sidereal",
|
|
817
|
+
... sidereal_mode="LAHIRI"
|
|
818
|
+
... )
|
|
819
|
+
|
|
820
|
+
Note:
|
|
821
|
+
- The exact time is captured at method execution, including seconds
|
|
822
|
+
- For horary astrology, consider the moment of understanding the question
|
|
823
|
+
- System clock accuracy affects precision; ensure accurate system time
|
|
824
|
+
- Time zone detection is automatic when using online location lookup
|
|
435
825
|
"""
|
|
436
826
|
now = datetime.now()
|
|
437
827
|
|
|
@@ -460,7 +850,32 @@ class AstrologicalSubjectFactory:
|
|
|
460
850
|
|
|
461
851
|
@classmethod
|
|
462
852
|
def _calculate_time_conversions(cls, data: Dict[str, Any], location: LocationData) -> None:
|
|
463
|
-
"""
|
|
853
|
+
"""
|
|
854
|
+
Calculate time conversions between local time, UTC, and Julian Day Number.
|
|
855
|
+
|
|
856
|
+
Handles timezone-aware conversion from local civil time to UTC and astronomical
|
|
857
|
+
Julian Day Number, including proper DST handling and timezone localization.
|
|
858
|
+
|
|
859
|
+
Args:
|
|
860
|
+
data (Dict[str, Any]): Calculation data dictionary containing time components
|
|
861
|
+
(year, month, day, hour, minute, seconds) and optional DST flag.
|
|
862
|
+
location (LocationData): Location data containing timezone information.
|
|
863
|
+
|
|
864
|
+
Raises:
|
|
865
|
+
KerykeionException: If DST ambiguity occurs during timezone transitions
|
|
866
|
+
and is_dst parameter is not explicitly set to resolve the ambiguity.
|
|
867
|
+
|
|
868
|
+
Side Effects:
|
|
869
|
+
Updates data dictionary with:
|
|
870
|
+
- iso_formatted_utc_datetime: ISO 8601 UTC timestamp
|
|
871
|
+
- iso_formatted_local_datetime: ISO 8601 local timestamp
|
|
872
|
+
- julian_day: Julian Day Number for astronomical calculations
|
|
873
|
+
|
|
874
|
+
Note:
|
|
875
|
+
During DST transitions, times may be ambiguous (fall back) or non-existent
|
|
876
|
+
(spring forward). The method raises an exception for ambiguous times unless
|
|
877
|
+
the is_dst parameter is explicitly set to True or False.
|
|
878
|
+
"""
|
|
464
879
|
# Convert local time to UTC
|
|
465
880
|
local_timezone = pytz.timezone(location.tz_str)
|
|
466
881
|
naive_datetime = datetime(
|
|
@@ -486,7 +901,37 @@ class AstrologicalSubjectFactory:
|
|
|
486
901
|
|
|
487
902
|
@classmethod
|
|
488
903
|
def _setup_ephemeris(cls, data: Dict[str, Any], config: ChartConfiguration) -> None:
|
|
489
|
-
"""
|
|
904
|
+
"""
|
|
905
|
+
Configure Swiss Ephemeris with appropriate calculation flags and settings.
|
|
906
|
+
|
|
907
|
+
Sets up the Swiss Ephemeris library with the correct ephemeris data path,
|
|
908
|
+
calculation flags for the specified perspective type, and sidereal mode
|
|
909
|
+
configuration if applicable.
|
|
910
|
+
|
|
911
|
+
Args:
|
|
912
|
+
data (Dict[str, Any]): Calculation data dictionary to store configuration.
|
|
913
|
+
config (ChartConfiguration): Validated chart configuration settings.
|
|
914
|
+
|
|
915
|
+
Side Effects:
|
|
916
|
+
- Sets Swiss Ephemeris data path to bundled ephemeris files
|
|
917
|
+
- Configures calculation flags (SWIEPH, SPEED, perspective flags)
|
|
918
|
+
- Sets sidereal mode for sidereal zodiac calculations
|
|
919
|
+
- Sets topocentric observer coordinates for topocentric perspective
|
|
920
|
+
- Updates data dictionary with houses_system_name and _iflag
|
|
921
|
+
|
|
922
|
+
Calculation Flags Set:
|
|
923
|
+
- FLG_SWIEPH: Use Swiss Ephemeris data files
|
|
924
|
+
- FLG_SPEED: Calculate planetary velocities
|
|
925
|
+
- FLG_TRUEPOS: True geometric positions (True Geocentric)
|
|
926
|
+
- FLG_HELCTR: Heliocentric coordinates (Heliocentric perspective)
|
|
927
|
+
- FLG_TOPOCTR: Topocentric coordinates (Topocentric perspective)
|
|
928
|
+
- FLG_SIDEREAL: Sidereal calculations (Sidereal zodiac)
|
|
929
|
+
|
|
930
|
+
Note:
|
|
931
|
+
The method assumes the Swiss Ephemeris data files are located in the
|
|
932
|
+
'sweph' subdirectory relative to this module. For topocentric calculations,
|
|
933
|
+
observer coordinates must be set via longitude, latitude, and altitude.
|
|
934
|
+
"""
|
|
490
935
|
# Set ephemeris path
|
|
491
936
|
swe.set_ephe_path(str(Path(__file__).parent.absolute() / "sweph"))
|
|
492
937
|
|
|
@@ -519,7 +964,42 @@ class AstrologicalSubjectFactory:
|
|
|
519
964
|
|
|
520
965
|
@classmethod
|
|
521
966
|
def _calculate_houses(cls, data: Dict[str, Any], active_points: Optional[List[AstrologicalPoint]]) -> None:
|
|
522
|
-
"""
|
|
967
|
+
"""
|
|
968
|
+
Calculate house cusps and angular points (Ascendant, MC, etc.).
|
|
969
|
+
|
|
970
|
+
Computes the 12 house cusps using the specified house system and calculates
|
|
971
|
+
the four main angles of the chart. Only calculates angular points that are
|
|
972
|
+
included in the active_points list for performance optimization.
|
|
973
|
+
|
|
974
|
+
Args:
|
|
975
|
+
data (Dict[str, Any]): Calculation data dictionary containing configuration
|
|
976
|
+
and location information. Updated with calculated house and angle data.
|
|
977
|
+
active_points (Optional[List[AstrologicalPoint]]): List of points to calculate.
|
|
978
|
+
If None, all points are calculated. Angular points not in this list
|
|
979
|
+
are skipped for performance.
|
|
980
|
+
|
|
981
|
+
Side Effects:
|
|
982
|
+
Updates data dictionary with:
|
|
983
|
+
- House cusp objects: first_house through twelfth_house
|
|
984
|
+
- Angular points: ascendant, medium_coeli, descendant, imum_coeli
|
|
985
|
+
- houses_names_list: List of all house names
|
|
986
|
+
- _houses_degree_ut: Raw house cusp degrees for internal use
|
|
987
|
+
|
|
988
|
+
House Systems Supported:
|
|
989
|
+
All systems supported by Swiss Ephemeris including Placidus, Koch,
|
|
990
|
+
Equal House, Whole Sign, Regiomontanus, Campanus, Topocentric, etc.
|
|
991
|
+
|
|
992
|
+
Angular Points Calculated:
|
|
993
|
+
- Ascendant: Eastern horizon point (1st house cusp)
|
|
994
|
+
- Medium Coeli (Midheaven): Southern meridian point (10th house cusp)
|
|
995
|
+
- Descendant: Western horizon point (opposite Ascendant)
|
|
996
|
+
- Imum Coeli: Northern meridian point (opposite Medium Coeli)
|
|
997
|
+
|
|
998
|
+
Note:
|
|
999
|
+
House calculations respect the zodiac type (Tropical/Sidereal) and use
|
|
1000
|
+
the appropriate Swiss Ephemeris function. Angular points include house
|
|
1001
|
+
position and retrograde status (always False for angles).
|
|
1002
|
+
"""
|
|
523
1003
|
# Skip calculation if point is not in active_points
|
|
524
1004
|
def should_calculate(point: AstrologicalPoint) -> bool:
|
|
525
1005
|
return not active_points or point in active_points
|
|
@@ -611,18 +1091,45 @@ class AstrologicalSubjectFactory:
|
|
|
611
1091
|
active_points: List[AstrologicalPoint]
|
|
612
1092
|
) -> None:
|
|
613
1093
|
"""
|
|
614
|
-
Calculate a single
|
|
1094
|
+
Calculate a single celestial body's position with comprehensive error handling.
|
|
1095
|
+
|
|
1096
|
+
Computes the position of a single planet, asteroid, or other celestial object
|
|
1097
|
+
using Swiss Ephemeris, creates a Kerykeion point object, determines house
|
|
1098
|
+
position, and assesses retrograde status. Handles calculation errors gracefully
|
|
1099
|
+
by logging and removing failed points from the active list.
|
|
615
1100
|
|
|
616
1101
|
Args:
|
|
617
|
-
data:
|
|
618
|
-
planet_name: Name
|
|
619
|
-
planet_id: Swiss Ephemeris
|
|
620
|
-
julian_day: Julian
|
|
621
|
-
iflag: Swiss Ephemeris calculation flags
|
|
622
|
-
houses_degree_ut: House degrees for house
|
|
623
|
-
point_type:
|
|
624
|
-
calculated_planets
|
|
625
|
-
active_points
|
|
1102
|
+
data (Dict[str, Any]): Main calculation data dictionary to store results.
|
|
1103
|
+
planet_name (AstrologicalPoint): Name identifier for the celestial body.
|
|
1104
|
+
planet_id (int): Swiss Ephemeris numerical identifier for the object.
|
|
1105
|
+
julian_day (float): Julian Day Number for the calculation moment.
|
|
1106
|
+
iflag (int): Swiss Ephemeris calculation flags (perspective, zodiac, etc.).
|
|
1107
|
+
houses_degree_ut (List[float]): House cusp degrees for house determination.
|
|
1108
|
+
point_type (PointType): Classification of the point type for the object.
|
|
1109
|
+
calculated_planets (List[str]): Running list of successfully calculated objects.
|
|
1110
|
+
active_points (List[AstrologicalPoint]): Active points list (modified on error).
|
|
1111
|
+
|
|
1112
|
+
Side Effects:
|
|
1113
|
+
- Adds calculated object to data dictionary using lowercase planet_name as key
|
|
1114
|
+
- Appends planet_name to calculated_planets list on success
|
|
1115
|
+
- Removes planet_name from active_points list on calculation failure
|
|
1116
|
+
- Logs error messages for calculation failures
|
|
1117
|
+
|
|
1118
|
+
Calculated Properties:
|
|
1119
|
+
- Zodiacal position (longitude) in degrees
|
|
1120
|
+
- House position based on house cusp positions
|
|
1121
|
+
- Retrograde status based on velocity (negative = retrograde)
|
|
1122
|
+
- Sign, degree, and minute components
|
|
1123
|
+
|
|
1124
|
+
Error Handling:
|
|
1125
|
+
If Swiss Ephemeris calculation fails (e.g., for distant asteroids outside
|
|
1126
|
+
ephemeris range), the method logs the error and removes the object from
|
|
1127
|
+
active_points to prevent cascade failures.
|
|
1128
|
+
|
|
1129
|
+
Note:
|
|
1130
|
+
The method uses the Swiss Ephemeris calc_ut function which returns position
|
|
1131
|
+
and velocity data. Retrograde determination is based on the velocity
|
|
1132
|
+
component being negative (element index 3).
|
|
626
1133
|
"""
|
|
627
1134
|
try:
|
|
628
1135
|
# Calculate planet position using Swiss Ephemeris
|
|
@@ -649,7 +1156,88 @@ class AstrologicalSubjectFactory:
|
|
|
649
1156
|
|
|
650
1157
|
@classmethod
|
|
651
1158
|
def _calculate_planets(cls, data: Dict[str, Any], active_points: List[AstrologicalPoint]) -> None:
|
|
652
|
-
"""
|
|
1159
|
+
"""
|
|
1160
|
+
Calculate positions for all requested celestial bodies and special points.
|
|
1161
|
+
|
|
1162
|
+
This comprehensive method calculates positions for a wide range of astrological
|
|
1163
|
+
points including traditional planets, lunar nodes, asteroids, trans-Neptunian
|
|
1164
|
+
objects, fixed stars, Arabic parts, and specialized points like Vertex.
|
|
1165
|
+
|
|
1166
|
+
The calculation is performed selectively based on the active_points list for
|
|
1167
|
+
performance optimization. Some Arabic parts automatically activate their
|
|
1168
|
+
prerequisite points if needed.
|
|
1169
|
+
|
|
1170
|
+
Args:
|
|
1171
|
+
data (Dict[str, Any]): Main calculation data dictionary. Updated with all
|
|
1172
|
+
calculated planetary positions and related metadata.
|
|
1173
|
+
active_points (List[AstrologicalPoint]): Mutable list of points to calculate.
|
|
1174
|
+
Modified during execution to remove failed calculations and add
|
|
1175
|
+
automatically required points for Arabic parts.
|
|
1176
|
+
|
|
1177
|
+
Celestial Bodies Calculated:
|
|
1178
|
+
Traditional Planets:
|
|
1179
|
+
- Sun, Moon, Mercury, Venus, Mars, Jupiter, Saturn
|
|
1180
|
+
- Uranus, Neptune, Pluto
|
|
1181
|
+
|
|
1182
|
+
Lunar Nodes:
|
|
1183
|
+
- Mean Node, True Node (North nodes)
|
|
1184
|
+
- Mean South Node, True South Node (calculated as opposites)
|
|
1185
|
+
|
|
1186
|
+
Lilith Points:
|
|
1187
|
+
- Mean Lilith (Mean Black Moon Lilith)
|
|
1188
|
+
- True Lilith (Osculating Black Moon Lilith)
|
|
1189
|
+
|
|
1190
|
+
Asteroids:
|
|
1191
|
+
- Ceres, Pallas, Juno, Vesta (main belt asteroids)
|
|
1192
|
+
|
|
1193
|
+
Centaurs:
|
|
1194
|
+
- Chiron, Pholus
|
|
1195
|
+
|
|
1196
|
+
Trans-Neptunian Objects:
|
|
1197
|
+
- Eris, Sedna, Haumea, Makemake
|
|
1198
|
+
- Ixion, Orcus, Quaoar
|
|
1199
|
+
|
|
1200
|
+
Fixed Stars:
|
|
1201
|
+
- Regulus, Spica (examples, extensible)
|
|
1202
|
+
|
|
1203
|
+
Arabic Parts (Lots):
|
|
1204
|
+
- Pars Fortunae (Part of Fortune)
|
|
1205
|
+
- Pars Spiritus (Part of Spirit)
|
|
1206
|
+
- Pars Amoris (Part of Love/Eros)
|
|
1207
|
+
- Pars Fidei (Part of Faith)
|
|
1208
|
+
|
|
1209
|
+
Special Points:
|
|
1210
|
+
- Earth (for heliocentric perspectives)
|
|
1211
|
+
- Vertex and Anti-Vertex
|
|
1212
|
+
|
|
1213
|
+
Side Effects:
|
|
1214
|
+
- Updates data dictionary with all calculated positions
|
|
1215
|
+
- Modifies active_points list by removing failed calculations
|
|
1216
|
+
- Adds prerequisite points for Arabic parts calculations
|
|
1217
|
+
- Updates data["active_points"] with successfully calculated objects
|
|
1218
|
+
|
|
1219
|
+
Error Handling:
|
|
1220
|
+
Individual calculation failures (e.g., asteroids outside ephemeris range)
|
|
1221
|
+
are handled gracefully with logging and removal from active_points.
|
|
1222
|
+
This prevents cascade failures while maintaining calculation integrity.
|
|
1223
|
+
|
|
1224
|
+
Arabic Parts Logic:
|
|
1225
|
+
- Day/night birth detection based on Sun's house position
|
|
1226
|
+
- Automatic activation of required base points (Sun, Moon, Ascendant, etc.)
|
|
1227
|
+
- Classical formulae with day/night variations where applicable
|
|
1228
|
+
- All parts marked as non-retrograde (conceptual points)
|
|
1229
|
+
|
|
1230
|
+
Performance Notes:
|
|
1231
|
+
- Only points in active_points are calculated (selective computation)
|
|
1232
|
+
- Failed calculations are removed to prevent repeated attempts
|
|
1233
|
+
- Some expensive calculations (like distant TNOs) may timeout
|
|
1234
|
+
- Fixed stars use different calculation methods than planets
|
|
1235
|
+
|
|
1236
|
+
Note:
|
|
1237
|
+
The method maintains a running list of successfully calculated planets
|
|
1238
|
+
and updates the active_points list to reflect actual availability.
|
|
1239
|
+
This ensures that dependent calculations and aspects only use valid data.
|
|
1240
|
+
"""
|
|
653
1241
|
# Skip calculation if point is not in active_points
|
|
654
1242
|
def should_calculate(point: AstrologicalPoint) -> bool:
|
|
655
1243
|
return not active_points or point in active_points
|
|
@@ -908,7 +1496,7 @@ class AstrologicalSubjectFactory:
|
|
|
908
1496
|
# Calculate Regulus (example fixed star)
|
|
909
1497
|
if should_calculate("Regulus"):
|
|
910
1498
|
try:
|
|
911
|
-
star_name =
|
|
1499
|
+
star_name = "Regulus"
|
|
912
1500
|
swe.fixstar_ut(star_name, julian_day, iflag)
|
|
913
1501
|
regulus_deg = swe.fixstar_ut(star_name, julian_day, iflag)[0][0]
|
|
914
1502
|
data["regulus"] = get_kerykeion_point_from_degree(regulus_deg, "Regulus", point_type=point_type)
|
|
@@ -922,7 +1510,7 @@ class AstrologicalSubjectFactory:
|
|
|
922
1510
|
# Calculate Spica (example fixed star)
|
|
923
1511
|
if should_calculate("Spica"):
|
|
924
1512
|
try:
|
|
925
|
-
star_name =
|
|
1513
|
+
star_name = "Spica"
|
|
926
1514
|
swe.fixstar_ut(star_name, julian_day, iflag)
|
|
927
1515
|
spica_deg = swe.fixstar_ut(star_name, julian_day, iflag)[0][0]
|
|
928
1516
|
data["spica"] = get_kerykeion_point_from_degree(spica_deg, "Spica", point_type=point_type)
|
|
@@ -1121,7 +1709,25 @@ class AstrologicalSubjectFactory:
|
|
|
1121
1709
|
|
|
1122
1710
|
@classmethod
|
|
1123
1711
|
def _calculate_day_of_week(cls, data: Dict[str, Any]) -> None:
|
|
1124
|
-
"""
|
|
1712
|
+
"""
|
|
1713
|
+
Calculate the day of the week for the given astronomical event.
|
|
1714
|
+
|
|
1715
|
+
Determines the day of the week corresponding to the Julian Day Number
|
|
1716
|
+
of the astrological event using Swiss Ephemeris calendar functions.
|
|
1717
|
+
|
|
1718
|
+
Args:
|
|
1719
|
+
data (Dict[str, Any]): Calculation data dictionary containing julian_day.
|
|
1720
|
+
Updated with the calculated day_of_week string.
|
|
1721
|
+
|
|
1722
|
+
Side Effects:
|
|
1723
|
+
Updates data dictionary with:
|
|
1724
|
+
- day_of_week: Human-readable day name (e.g., "Monday", "Tuesday")
|
|
1725
|
+
|
|
1726
|
+
Note:
|
|
1727
|
+
The Swiss Ephemeris day_of_week function returns an integer where
|
|
1728
|
+
0=Monday, 1=Tuesday, ..., 6=Sunday. This is converted to readable
|
|
1729
|
+
day names for user convenience.
|
|
1730
|
+
"""
|
|
1125
1731
|
# Calculate the day of the week (0=Sunday, 1=Monday, ..., 6=Saturday)
|
|
1126
1732
|
day_of_week = swe.day_of_week(data["julian_day"])
|
|
1127
1733
|
# Map to human-readable names
|