kerykeion 4.26.2__py3-none-any.whl → 5.0.0a1__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 +8 -5
- kerykeion/aspects/aspects_utils.py +14 -8
- kerykeion/aspects/natal_aspects.py +26 -17
- kerykeion/aspects/synastry_aspects.py +32 -15
- kerykeion/aspects/transits_time_range.py +2 -2
- kerykeion/astrological_subject_factory.py +1132 -0
- kerykeion/charts/charts_utils.py +583 -85
- kerykeion/charts/draw_planets.py +9 -8
- kerykeion/charts/draw_planets_v2.py +639 -0
- kerykeion/charts/kerykeion_chart_svg.py +1289 -592
- kerykeion/charts/templates/chart.xml +178 -79
- kerykeion/charts/templates/wheel_only.xml +13 -12
- kerykeion/charts/themes/classic.css +91 -76
- kerykeion/charts/themes/dark-high-contrast.css +129 -107
- kerykeion/charts/themes/dark.css +130 -107
- kerykeion/charts/themes/light.css +130 -103
- kerykeion/charts/themes/strawberry.css +143 -0
- kerykeion/composite_subject_factory.py +26 -43
- kerykeion/ephemeris_data.py +6 -10
- kerykeion/house_comparison/__init__.py +3 -0
- kerykeion/house_comparison/house_comparison_factory.py +70 -0
- kerykeion/house_comparison/house_comparison_models.py +38 -0
- kerykeion/house_comparison/house_comparison_utils.py +98 -0
- kerykeion/kr_types/chart_types.py +9 -3
- kerykeion/kr_types/kr_literals.py +34 -6
- kerykeion/kr_types/kr_models.py +122 -160
- kerykeion/kr_types/settings_models.py +107 -143
- kerykeion/planetary_return_factory.py +299 -0
- kerykeion/relationship_score/relationship_score.py +3 -3
- kerykeion/relationship_score/relationship_score_factory.py +9 -12
- kerykeion/report.py +4 -4
- kerykeion/settings/config_constants.py +35 -6
- kerykeion/settings/kerykeion_settings.py +1 -0
- kerykeion/settings/kr.config.json +1301 -1255
- kerykeion/settings/legacy/__init__.py +0 -0
- kerykeion/settings/legacy/legacy_celestial_points_settings.py +299 -0
- kerykeion/settings/legacy/legacy_chart_aspects_settings.py +71 -0
- kerykeion/settings/legacy/legacy_color_settings.py +42 -0
- kerykeion/transits_time_range.py +13 -9
- kerykeion/utilities.py +228 -31
- {kerykeion-4.26.2.dist-info → kerykeion-5.0.0a1.dist-info}/METADATA +3 -3
- kerykeion-5.0.0a1.dist-info/RECORD +56 -0
- {kerykeion-4.26.2.dist-info → kerykeion-5.0.0a1.dist-info}/WHEEL +1 -1
- kerykeion/astrological_subject.py +0 -841
- kerykeion-4.26.2.dist-info/LICENSE +0 -661
- kerykeion-4.26.2.dist-info/RECORD +0 -46
- /LICENSE → /kerykeion-5.0.0a1.dist-info/LICENSE +0 -0
- {kerykeion-4.26.2.dist-info → kerykeion-5.0.0a1.dist-info}/entry_points.txt +0 -0
|
@@ -1,841 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
This is part of Kerykeion (C) 2025 Giacomo Battaglia
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import pytz
|
|
7
|
-
import swisseph as swe
|
|
8
|
-
import logging
|
|
9
|
-
import warnings
|
|
10
|
-
|
|
11
|
-
import math
|
|
12
|
-
from datetime import datetime
|
|
13
|
-
|
|
14
|
-
from functools import cached_property
|
|
15
|
-
from kerykeion.fetch_geonames import FetchGeonames
|
|
16
|
-
from kerykeion.kr_types import (
|
|
17
|
-
KerykeionException,
|
|
18
|
-
ZodiacType,
|
|
19
|
-
AstrologicalSubjectModel,
|
|
20
|
-
LunarPhaseModel,
|
|
21
|
-
KerykeionPointModel,
|
|
22
|
-
PointType,
|
|
23
|
-
SiderealMode,
|
|
24
|
-
HousesSystemIdentifier,
|
|
25
|
-
PerspectiveType,
|
|
26
|
-
Planet,
|
|
27
|
-
Houses,
|
|
28
|
-
AxialCusps,
|
|
29
|
-
)
|
|
30
|
-
from kerykeion.utilities import (
|
|
31
|
-
get_number_from_name,
|
|
32
|
-
get_kerykeion_point_from_degree,
|
|
33
|
-
get_planet_house,
|
|
34
|
-
check_and_adjust_polar_latitude,
|
|
35
|
-
calculate_moon_phase
|
|
36
|
-
)
|
|
37
|
-
from pathlib import Path
|
|
38
|
-
from typing import Union, get_args
|
|
39
|
-
|
|
40
|
-
DEFAULT_GEONAMES_USERNAME = "century.boy"
|
|
41
|
-
DEFAULT_SIDEREAL_MODE: SiderealMode = "FAGAN_BRADLEY"
|
|
42
|
-
DEFAULT_HOUSES_SYSTEM_IDENTIFIER: HousesSystemIdentifier = "P"
|
|
43
|
-
DEFAULT_ZODIAC_TYPE: ZodiacType = "Tropic"
|
|
44
|
-
DEFAULT_PERSPECTIVE_TYPE: PerspectiveType = "Apparent Geocentric"
|
|
45
|
-
DEFAULT_GEONAMES_CACHE_EXPIRE_AFTER_DAYS = 30
|
|
46
|
-
GEONAMES_DEFAULT_USERNAME_WARNING = (
|
|
47
|
-
"\n********\n"
|
|
48
|
-
"NO GEONAMES USERNAME SET!\n"
|
|
49
|
-
"Using the default geonames username is not recommended, please set a custom one!\n"
|
|
50
|
-
"You can get one for free here:\n"
|
|
51
|
-
"https://www.geonames.org/login\n"
|
|
52
|
-
"Keep in mind that the default username is limited to 2000 requests per hour and is shared with everyone else using this library.\n"
|
|
53
|
-
"********"
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
NOW = datetime.now()
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class AstrologicalSubject:
|
|
60
|
-
"""
|
|
61
|
-
Calculates all the astrological information, the coordinates,
|
|
62
|
-
it's utc and julian day and returns an object with all that data.
|
|
63
|
-
|
|
64
|
-
Args:
|
|
65
|
-
- name (str, optional): The name of the subject. Defaults to "Now".
|
|
66
|
-
- year (int, optional): The year of birth. Defaults to the current year.
|
|
67
|
-
- month (int, optional): The month of birth. Defaults to the current month.
|
|
68
|
-
- day (int, optional): The day of birth. Defaults to the current day.
|
|
69
|
-
- hour (int, optional): The hour of birth. Defaults to the current hour.
|
|
70
|
-
- minute (int, optional): Defaults to the current minute.
|
|
71
|
-
- city (str, optional): City or location of birth. Defaults to "London", which is GMT time.
|
|
72
|
-
The city argument is used to get the coordinates and timezone from geonames just in case
|
|
73
|
-
you don't insert them manually (see _get_tz).
|
|
74
|
-
If you insert the coordinates and timezone manually, the city argument is not used for calculations
|
|
75
|
-
but it's still used as a value for the city attribute.
|
|
76
|
-
- nat (str, optional): _ Defaults to "".
|
|
77
|
-
- lng (Union[int, float], optional): Longitude of the birth location. Defaults to 0 (Greenwich, London).
|
|
78
|
-
- lat (Union[int, float], optional): Latitude of the birth location. Defaults to 51.5074 (Greenwich, London).
|
|
79
|
-
- tz_str (Union[str, bool], optional): Timezone of the birth location. Defaults to "GMT".
|
|
80
|
-
- geonames_username (str, optional): The username for the geonames API. Note: Change this to your own username to avoid rate limits!
|
|
81
|
-
You can get one for free here: https://www.geonames.org/login
|
|
82
|
-
- online (bool, optional): Sets if you want to use the online mode, which fetches the timezone and coordinates from geonames.
|
|
83
|
-
If you already have the coordinates and timezone, set this to False. Defaults to True.
|
|
84
|
-
- disable_chiron: Deprecated, use disable_chiron_and_lilith instead.
|
|
85
|
-
- sidereal_mode (SiderealMode, optional): Also known as Ayanamsa.
|
|
86
|
-
The mode to use for the sidereal zodiac, according to the Swiss Ephemeris.
|
|
87
|
-
Defaults to "FAGAN_BRADLEY".
|
|
88
|
-
Available modes are visible in the SiderealMode Literal.
|
|
89
|
-
- houses_system_identifier (HousesSystemIdentifier, optional): The system to use for the calculation of the houses.
|
|
90
|
-
Defaults to "P" (Placidus).
|
|
91
|
-
Available systems are visible in the HousesSystemIdentifier Literal.
|
|
92
|
-
- perspective_type (PerspectiveType, optional): The perspective to use for the calculation of the chart.
|
|
93
|
-
Defaults to "Apparent Geocentric".
|
|
94
|
-
Available perspectives are visible in the PerspectiveType Literal.
|
|
95
|
-
- cache_expire_after_days (int, optional): The number of days after which the geonames cache will expire. Defaults to 30.
|
|
96
|
-
- is_dst (Union[None, bool], optional): Specify if the time is in DST. Defaults to None.
|
|
97
|
-
By default (None), the library will try to guess if the time is in DST or not and raise an AmbiguousTimeError
|
|
98
|
-
if it can't guess. If you know the time is in DST, set this to True, if you know it's not, set it to False.
|
|
99
|
-
- disable_chiron_and_lilith (bool, optional): boolean representing if Chiron and Lilith should be disabled. Default is False.
|
|
100
|
-
Chiron calculation can create some issues with the Swiss Ephemeris when the date is too far in the past.
|
|
101
|
-
"""
|
|
102
|
-
|
|
103
|
-
# Defined by the user
|
|
104
|
-
name: str
|
|
105
|
-
year: int
|
|
106
|
-
month: int
|
|
107
|
-
day: int
|
|
108
|
-
hour: int
|
|
109
|
-
minute: int
|
|
110
|
-
city: str
|
|
111
|
-
nation: str
|
|
112
|
-
lng: Union[int, float]
|
|
113
|
-
lat: Union[int, float]
|
|
114
|
-
tz_str: str
|
|
115
|
-
geonames_username: str
|
|
116
|
-
online: bool
|
|
117
|
-
zodiac_type: ZodiacType
|
|
118
|
-
sidereal_mode: Union[SiderealMode, None]
|
|
119
|
-
houses_system_identifier: HousesSystemIdentifier
|
|
120
|
-
houses_system_name: str
|
|
121
|
-
perspective_type: PerspectiveType
|
|
122
|
-
is_dst: Union[None, bool]
|
|
123
|
-
|
|
124
|
-
# Generated internally
|
|
125
|
-
city_data: dict[str, str]
|
|
126
|
-
julian_day: Union[int, float]
|
|
127
|
-
json_dir: Path
|
|
128
|
-
iso_formatted_local_datetime: str
|
|
129
|
-
iso_formatted_utc_datetime: str
|
|
130
|
-
|
|
131
|
-
# Planets
|
|
132
|
-
sun: KerykeionPointModel
|
|
133
|
-
moon: KerykeionPointModel
|
|
134
|
-
mercury: KerykeionPointModel
|
|
135
|
-
venus: KerykeionPointModel
|
|
136
|
-
mars: KerykeionPointModel
|
|
137
|
-
jupiter: KerykeionPointModel
|
|
138
|
-
saturn: KerykeionPointModel
|
|
139
|
-
uranus: KerykeionPointModel
|
|
140
|
-
neptune: KerykeionPointModel
|
|
141
|
-
pluto: KerykeionPointModel
|
|
142
|
-
true_node: KerykeionPointModel
|
|
143
|
-
mean_node: KerykeionPointModel
|
|
144
|
-
chiron: Union[KerykeionPointModel, None]
|
|
145
|
-
mean_lilith: Union[KerykeionPointModel, None]
|
|
146
|
-
true_south_node: KerykeionPointModel
|
|
147
|
-
mean_south_node: KerykeionPointModel
|
|
148
|
-
|
|
149
|
-
# Axes
|
|
150
|
-
asc: KerykeionPointModel
|
|
151
|
-
dsc: KerykeionPointModel
|
|
152
|
-
mc: KerykeionPointModel
|
|
153
|
-
ic: KerykeionPointModel
|
|
154
|
-
|
|
155
|
-
# Houses
|
|
156
|
-
first_house: KerykeionPointModel
|
|
157
|
-
second_house: KerykeionPointModel
|
|
158
|
-
third_house: KerykeionPointModel
|
|
159
|
-
fourth_house: KerykeionPointModel
|
|
160
|
-
fifth_house: KerykeionPointModel
|
|
161
|
-
sixth_house: KerykeionPointModel
|
|
162
|
-
seventh_house: KerykeionPointModel
|
|
163
|
-
eighth_house: KerykeionPointModel
|
|
164
|
-
ninth_house: KerykeionPointModel
|
|
165
|
-
tenth_house: KerykeionPointModel
|
|
166
|
-
eleventh_house: KerykeionPointModel
|
|
167
|
-
twelfth_house: KerykeionPointModel
|
|
168
|
-
|
|
169
|
-
# Lists
|
|
170
|
-
_houses_list: list[KerykeionPointModel]
|
|
171
|
-
_houses_degree_ut: list[float]
|
|
172
|
-
planets_names_list: list[Planet]
|
|
173
|
-
houses_names_list: list[Houses]
|
|
174
|
-
axial_cusps_names_list: list[AxialCusps]
|
|
175
|
-
|
|
176
|
-
# Enable or disable features
|
|
177
|
-
disable_chiron: Union[None, bool]
|
|
178
|
-
disable_chiron_and_lilith: bool
|
|
179
|
-
|
|
180
|
-
lunar_phase: LunarPhaseModel
|
|
181
|
-
|
|
182
|
-
def __init__(
|
|
183
|
-
self,
|
|
184
|
-
name="Now",
|
|
185
|
-
year: int = NOW.year,
|
|
186
|
-
month: int = NOW.month,
|
|
187
|
-
day: int = NOW.day,
|
|
188
|
-
hour: int = NOW.hour,
|
|
189
|
-
minute: int = NOW.minute,
|
|
190
|
-
city: Union[str, None] = None,
|
|
191
|
-
nation: Union[str, None] = None,
|
|
192
|
-
lng: Union[int, float, None] = None,
|
|
193
|
-
lat: Union[int, float, None] = None,
|
|
194
|
-
tz_str: Union[str, None] = None,
|
|
195
|
-
geonames_username: Union[str, None] = None,
|
|
196
|
-
zodiac_type: Union[ZodiacType, None] = DEFAULT_ZODIAC_TYPE,
|
|
197
|
-
online: bool = True,
|
|
198
|
-
disable_chiron: Union[None, bool] = None, # Deprecated
|
|
199
|
-
sidereal_mode: Union[SiderealMode, None] = None,
|
|
200
|
-
houses_system_identifier: Union[HousesSystemIdentifier, None] = DEFAULT_HOUSES_SYSTEM_IDENTIFIER,
|
|
201
|
-
perspective_type: Union[PerspectiveType, None] = DEFAULT_PERSPECTIVE_TYPE,
|
|
202
|
-
cache_expire_after_days: Union[int, None] = DEFAULT_GEONAMES_CACHE_EXPIRE_AFTER_DAYS,
|
|
203
|
-
is_dst: Union[None, bool] = None,
|
|
204
|
-
disable_chiron_and_lilith: bool = False
|
|
205
|
-
) -> None:
|
|
206
|
-
logging.debug("Starting Kerykeion")
|
|
207
|
-
|
|
208
|
-
# Deprecation warnings --->
|
|
209
|
-
if disable_chiron is not None:
|
|
210
|
-
warnings.warn(
|
|
211
|
-
"The 'disable_chiron' argument is deprecated and will be removed in a future version. "
|
|
212
|
-
"Please use 'disable_chiron' instead.",
|
|
213
|
-
DeprecationWarning
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
if disable_chiron_and_lilith:
|
|
217
|
-
raise ValueError("Cannot specify both 'disable_chiron' and 'disable_chiron_and_lilith'. Use 'disable_chiron_and_lilith' only.")
|
|
218
|
-
|
|
219
|
-
self.disable_chiron_and_lilith = disable_chiron
|
|
220
|
-
# <--- Deprecation warnings
|
|
221
|
-
|
|
222
|
-
self.name = name
|
|
223
|
-
self.year = year
|
|
224
|
-
self.month = month
|
|
225
|
-
self.day = day
|
|
226
|
-
self.hour = hour
|
|
227
|
-
self.minute = minute
|
|
228
|
-
self.online = online
|
|
229
|
-
self.json_dir = Path.home()
|
|
230
|
-
self.disable_chiron = disable_chiron
|
|
231
|
-
self.sidereal_mode = sidereal_mode
|
|
232
|
-
self.cache_expire_after_days = cache_expire_after_days
|
|
233
|
-
self.is_dst = is_dst
|
|
234
|
-
self.disable_chiron_and_lilith = disable_chiron_and_lilith
|
|
235
|
-
|
|
236
|
-
#---------------#
|
|
237
|
-
# General setup #
|
|
238
|
-
#---------------#
|
|
239
|
-
|
|
240
|
-
# Geonames username
|
|
241
|
-
if geonames_username is None and online and (not lat or not lng or not tz_str):
|
|
242
|
-
logging.warning(GEONAMES_DEFAULT_USERNAME_WARNING)
|
|
243
|
-
self.geonames_username = DEFAULT_GEONAMES_USERNAME
|
|
244
|
-
else:
|
|
245
|
-
self.geonames_username = geonames_username # type: ignore
|
|
246
|
-
|
|
247
|
-
# City
|
|
248
|
-
if not city:
|
|
249
|
-
self.city = "London"
|
|
250
|
-
logging.info("No city specified, using London as default")
|
|
251
|
-
else:
|
|
252
|
-
self.city = city
|
|
253
|
-
|
|
254
|
-
# Nation
|
|
255
|
-
if not nation:
|
|
256
|
-
self.nation = "GB"
|
|
257
|
-
logging.info("No nation specified, using GB as default")
|
|
258
|
-
else:
|
|
259
|
-
self.nation = nation
|
|
260
|
-
|
|
261
|
-
# Latitude
|
|
262
|
-
if not lat and not self.online:
|
|
263
|
-
self.lat = 51.5074
|
|
264
|
-
logging.info("No latitude specified, using London as default")
|
|
265
|
-
else:
|
|
266
|
-
self.lat = lat # type: ignore
|
|
267
|
-
|
|
268
|
-
# Longitude
|
|
269
|
-
if not lng and not self.online:
|
|
270
|
-
self.lng = 0
|
|
271
|
-
logging.info("No longitude specified, using London as default")
|
|
272
|
-
else:
|
|
273
|
-
self.lng = lng # type: ignore
|
|
274
|
-
|
|
275
|
-
# Timezone
|
|
276
|
-
if (not self.online) and (not tz_str):
|
|
277
|
-
raise KerykeionException("You need to set the coordinates and timezone if you want to use the offline mode!")
|
|
278
|
-
else:
|
|
279
|
-
self.tz_str = tz_str # type: ignore
|
|
280
|
-
|
|
281
|
-
# Zodiac type
|
|
282
|
-
if not zodiac_type:
|
|
283
|
-
self.zodiac_type = DEFAULT_ZODIAC_TYPE
|
|
284
|
-
else:
|
|
285
|
-
self.zodiac_type = zodiac_type
|
|
286
|
-
|
|
287
|
-
# Perspective type
|
|
288
|
-
if not perspective_type:
|
|
289
|
-
self.perspective_type = DEFAULT_PERSPECTIVE_TYPE
|
|
290
|
-
else:
|
|
291
|
-
self.perspective_type = perspective_type
|
|
292
|
-
|
|
293
|
-
# Houses system identifier
|
|
294
|
-
if not houses_system_identifier:
|
|
295
|
-
self.houses_system_identifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER
|
|
296
|
-
else:
|
|
297
|
-
self.houses_system_identifier = houses_system_identifier
|
|
298
|
-
|
|
299
|
-
# Cache expire after days
|
|
300
|
-
if not cache_expire_after_days:
|
|
301
|
-
self.cache_expire_after_days = DEFAULT_GEONAMES_CACHE_EXPIRE_AFTER_DAYS
|
|
302
|
-
else:
|
|
303
|
-
self.cache_expire_after_days = cache_expire_after_days
|
|
304
|
-
|
|
305
|
-
#-----------------------#
|
|
306
|
-
# Swiss Ephemeris setup #
|
|
307
|
-
#-----------------------#
|
|
308
|
-
|
|
309
|
-
# We set the swisseph path to the current directory
|
|
310
|
-
swe.set_ephe_path(str(Path(__file__).parent.absolute() / "sweph"))
|
|
311
|
-
|
|
312
|
-
# Flags for the Swiss Ephemeris
|
|
313
|
-
self._iflag = swe.FLG_SWIEPH + swe.FLG_SPEED
|
|
314
|
-
|
|
315
|
-
# Chart Perspective check and setup --->
|
|
316
|
-
if self.perspective_type not in get_args(PerspectiveType):
|
|
317
|
-
raise KerykeionException(f"\n* ERROR: '{self.perspective_type}' is NOT a valid chart perspective! Available perspectives are: *" + "\n" + str(get_args(PerspectiveType)))
|
|
318
|
-
|
|
319
|
-
if self.perspective_type == "True Geocentric":
|
|
320
|
-
self._iflag += swe.FLG_TRUEPOS
|
|
321
|
-
elif self.perspective_type == "Heliocentric":
|
|
322
|
-
self._iflag += swe.FLG_HELCTR
|
|
323
|
-
elif self.perspective_type == "Topocentric":
|
|
324
|
-
self._iflag += swe.FLG_TOPOCTR
|
|
325
|
-
# geopos_is_set, for topocentric
|
|
326
|
-
if (self.online) and (not self.tz_str) and (not self.lat) and (not self.lng):
|
|
327
|
-
self._fetch_and_set_tz_and_coordinates_from_geonames()
|
|
328
|
-
swe.set_topo(self.lng, self.lat, 0)
|
|
329
|
-
# <--- Chart Perspective check and setup
|
|
330
|
-
|
|
331
|
-
# House System check and setup --->
|
|
332
|
-
if self.houses_system_identifier not in get_args(HousesSystemIdentifier):
|
|
333
|
-
raise KerykeionException(f"\n* ERROR: '{self.houses_system_identifier}' is NOT a valid house system! Available systems are: *" + "\n" + str(get_args(HousesSystemIdentifier)))
|
|
334
|
-
|
|
335
|
-
self.houses_system_name = swe.house_name(self.houses_system_identifier.encode('ascii'))
|
|
336
|
-
# <--- House System check and setup
|
|
337
|
-
|
|
338
|
-
# Zodiac Type and Sidereal mode checks and setup --->
|
|
339
|
-
if zodiac_type and not zodiac_type in get_args(ZodiacType):
|
|
340
|
-
raise KerykeionException(f"\n* ERROR: '{zodiac_type}' is NOT a valid zodiac type! Available types are: *" + "\n" + str(get_args(ZodiacType)))
|
|
341
|
-
|
|
342
|
-
if self.sidereal_mode and self.zodiac_type == "Tropic":
|
|
343
|
-
raise KerykeionException("You can't set a sidereal mode with a Tropic zodiac type!")
|
|
344
|
-
|
|
345
|
-
if self.zodiac_type == "Sidereal" and not self.sidereal_mode:
|
|
346
|
-
self.sidereal_mode = DEFAULT_SIDEREAL_MODE
|
|
347
|
-
logging.info("No sidereal mode set, using default FAGAN_BRADLEY")
|
|
348
|
-
|
|
349
|
-
if self.zodiac_type == "Sidereal":
|
|
350
|
-
# Check if the sidereal mode is valid
|
|
351
|
-
|
|
352
|
-
if not self.sidereal_mode or not self.sidereal_mode in get_args(SiderealMode):
|
|
353
|
-
raise KerykeionException(f"\n* ERROR: '{self.sidereal_mode}' is NOT a valid sidereal mode! Available modes are: *" + "\n" + str(get_args(SiderealMode)))
|
|
354
|
-
|
|
355
|
-
self._iflag += swe.FLG_SIDEREAL
|
|
356
|
-
mode = "SIDM_" + self.sidereal_mode
|
|
357
|
-
swe.set_sid_mode(getattr(swe, mode))
|
|
358
|
-
logging.debug(f"Using sidereal mode: {mode}")
|
|
359
|
-
# <--- Zodiac Type and Sidereal mode checks and setup
|
|
360
|
-
|
|
361
|
-
#------------------------#
|
|
362
|
-
# Start the calculations #
|
|
363
|
-
#------------------------#
|
|
364
|
-
|
|
365
|
-
# UTC, julian day and local time setup --->
|
|
366
|
-
if (self.online) and (not self.tz_str) and (not self.lat) and (not self.lng):
|
|
367
|
-
self._fetch_and_set_tz_and_coordinates_from_geonames()
|
|
368
|
-
|
|
369
|
-
self.lat = check_and_adjust_polar_latitude(self.lat)
|
|
370
|
-
|
|
371
|
-
# Local time to UTC
|
|
372
|
-
local_time = pytz.timezone(self.tz_str)
|
|
373
|
-
naive_datetime = datetime(self.year, self.month, self.day, self.hour, self.minute, 0)
|
|
374
|
-
|
|
375
|
-
try:
|
|
376
|
-
local_datetime = local_time.localize(naive_datetime, is_dst=self.is_dst)
|
|
377
|
-
except pytz.exceptions.AmbiguousTimeError:
|
|
378
|
-
raise KerykeionException("Ambiguous time! Please specify if the time is in DST or not with the is_dst argument.")
|
|
379
|
-
|
|
380
|
-
utc_object = local_datetime.astimezone(pytz.utc)
|
|
381
|
-
self.iso_formatted_utc_datetime = utc_object.isoformat()
|
|
382
|
-
|
|
383
|
-
# ISO formatted local datetime
|
|
384
|
-
self.iso_formatted_local_datetime = local_datetime.isoformat()
|
|
385
|
-
|
|
386
|
-
# Julian day calculation
|
|
387
|
-
utc_float_hour_with_minutes = utc_object.hour + (utc_object.minute / 60)
|
|
388
|
-
self.julian_day = float(swe.julday(utc_object.year, utc_object.month, utc_object.day, utc_float_hour_with_minutes))
|
|
389
|
-
# <--- UTC, julian day and local time setup
|
|
390
|
-
|
|
391
|
-
# Planets and Houses setup
|
|
392
|
-
self._initialize_houses()
|
|
393
|
-
self._initialize_planets()
|
|
394
|
-
|
|
395
|
-
# Lunar Phase
|
|
396
|
-
self.lunar_phase = calculate_moon_phase(
|
|
397
|
-
self.moon.abs_pos,
|
|
398
|
-
self.sun.abs_pos
|
|
399
|
-
)
|
|
400
|
-
|
|
401
|
-
# Deprecated properties
|
|
402
|
-
self.utc_time
|
|
403
|
-
self.local_time
|
|
404
|
-
|
|
405
|
-
def __str__(self) -> str:
|
|
406
|
-
return f"Astrological data for: {self.name}, {self.iso_formatted_utc_datetime} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
|
|
407
|
-
|
|
408
|
-
def __repr__(self) -> str:
|
|
409
|
-
return f"Astrological data for: {self.name}, {self.iso_formatted_utc_datetime} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
|
|
410
|
-
|
|
411
|
-
def __getitem__(self, item):
|
|
412
|
-
return getattr(self, item)
|
|
413
|
-
|
|
414
|
-
def get(self, item, default=None):
|
|
415
|
-
return getattr(self, item, default)
|
|
416
|
-
|
|
417
|
-
def _fetch_and_set_tz_and_coordinates_from_geonames(self) -> None:
|
|
418
|
-
"""Gets the nearest time zone for the calculation"""
|
|
419
|
-
logging.info("Fetching timezone/coordinates from geonames")
|
|
420
|
-
|
|
421
|
-
geonames = FetchGeonames(
|
|
422
|
-
self.city,
|
|
423
|
-
self.nation,
|
|
424
|
-
username=self.geonames_username,
|
|
425
|
-
cache_expire_after_days=self.cache_expire_after_days
|
|
426
|
-
)
|
|
427
|
-
self.city_data: dict[str, str] = geonames.get_serialized_data()
|
|
428
|
-
|
|
429
|
-
if (
|
|
430
|
-
not "countryCode" in self.city_data
|
|
431
|
-
or not "timezonestr" in self.city_data
|
|
432
|
-
or not "lat" in self.city_data
|
|
433
|
-
or not "lng" in self.city_data
|
|
434
|
-
):
|
|
435
|
-
raise KerykeionException("No data found for this city, try again! Maybe check your connection?")
|
|
436
|
-
|
|
437
|
-
self.nation = self.city_data["countryCode"]
|
|
438
|
-
self.lng = float(self.city_data["lng"])
|
|
439
|
-
self.lat = float(self.city_data["lat"])
|
|
440
|
-
self.tz_str = self.city_data["timezonestr"]
|
|
441
|
-
|
|
442
|
-
def _initialize_houses(self) -> None:
|
|
443
|
-
"""
|
|
444
|
-
Calculate positions and store them in dictionaries
|
|
445
|
-
|
|
446
|
-
https://www.astro.com/faq/fq_fh_owhouse_e.htm
|
|
447
|
-
https://github.com/jwmatthys/pd-swisseph/blob/master/swehouse.c#L685
|
|
448
|
-
hsys = letter code for house system;
|
|
449
|
-
A equal
|
|
450
|
-
E equal
|
|
451
|
-
B Alcabitius
|
|
452
|
-
C Campanus
|
|
453
|
-
D equal (MC)
|
|
454
|
-
F Carter "Poli-Equatorial"
|
|
455
|
-
G 36 Gauquelin sectors
|
|
456
|
-
H horizon / azimut
|
|
457
|
-
I Sunshine solution Treindl
|
|
458
|
-
i Sunshine solution Makransky
|
|
459
|
-
K Koch
|
|
460
|
-
L Pullen SD "sinusoidal delta", ex Neo-Porphyry
|
|
461
|
-
M Morinus
|
|
462
|
-
N equal/1=Aries
|
|
463
|
-
O Porphyry
|
|
464
|
-
P Placidus
|
|
465
|
-
Q Pullen SR "sinusoidal ratio"
|
|
466
|
-
R Regiomontanus
|
|
467
|
-
S Sripati
|
|
468
|
-
T Polich/Page ("topocentric")
|
|
469
|
-
U Krusinski-Pisa-Goelzer
|
|
470
|
-
V equal Vehlow
|
|
471
|
-
W equal, whole sign
|
|
472
|
-
X axial rotation system/ Meridian houses
|
|
473
|
-
Y APC houses
|
|
474
|
-
"""
|
|
475
|
-
|
|
476
|
-
_ascmc = (-1.0, -1.0)
|
|
477
|
-
|
|
478
|
-
if self.zodiac_type == "Sidereal":
|
|
479
|
-
cusps, ascmc = swe.houses_ex(
|
|
480
|
-
tjdut=self.julian_day,
|
|
481
|
-
lat=self.lat, lon=self.lng,
|
|
482
|
-
hsys=str.encode(self.houses_system_identifier),
|
|
483
|
-
flags=swe.FLG_SIDEREAL
|
|
484
|
-
)
|
|
485
|
-
self._houses_degree_ut = cusps
|
|
486
|
-
_ascmc = ascmc
|
|
487
|
-
|
|
488
|
-
elif self.zodiac_type == "Tropic":
|
|
489
|
-
cusps, ascmc = swe.houses(
|
|
490
|
-
tjdut=self.julian_day, lat=self.lat,
|
|
491
|
-
lon=self.lng,
|
|
492
|
-
hsys=str.encode(self.houses_system_identifier)
|
|
493
|
-
)
|
|
494
|
-
self._houses_degree_ut = cusps
|
|
495
|
-
_ascmc = ascmc
|
|
496
|
-
|
|
497
|
-
else:
|
|
498
|
-
raise KerykeionException("Not a valid zodiac type: " + self.zodiac_type)
|
|
499
|
-
|
|
500
|
-
point_type: PointType = "House"
|
|
501
|
-
|
|
502
|
-
# stores the house in singular dictionaries.
|
|
503
|
-
self.first_house = get_kerykeion_point_from_degree(self._houses_degree_ut[0], "First_House", point_type=point_type)
|
|
504
|
-
self.second_house = get_kerykeion_point_from_degree(self._houses_degree_ut[1], "Second_House", point_type=point_type)
|
|
505
|
-
self.third_house = get_kerykeion_point_from_degree(self._houses_degree_ut[2], "Third_House", point_type=point_type)
|
|
506
|
-
self.fourth_house = get_kerykeion_point_from_degree(self._houses_degree_ut[3], "Fourth_House", point_type=point_type)
|
|
507
|
-
self.fifth_house = get_kerykeion_point_from_degree(self._houses_degree_ut[4], "Fifth_House", point_type=point_type)
|
|
508
|
-
self.sixth_house = get_kerykeion_point_from_degree(self._houses_degree_ut[5], "Sixth_House", point_type=point_type)
|
|
509
|
-
self.seventh_house = get_kerykeion_point_from_degree(self._houses_degree_ut[6], "Seventh_House", point_type=point_type)
|
|
510
|
-
self.eighth_house = get_kerykeion_point_from_degree(self._houses_degree_ut[7], "Eighth_House", point_type=point_type)
|
|
511
|
-
self.ninth_house = get_kerykeion_point_from_degree(self._houses_degree_ut[8], "Ninth_House", point_type=point_type)
|
|
512
|
-
self.tenth_house = get_kerykeion_point_from_degree(self._houses_degree_ut[9], "Tenth_House", point_type=point_type)
|
|
513
|
-
self.eleventh_house = get_kerykeion_point_from_degree(self._houses_degree_ut[10], "Eleventh_House", point_type=point_type)
|
|
514
|
-
self.twelfth_house = get_kerykeion_point_from_degree(self._houses_degree_ut[11], "Twelfth_House", point_type=point_type)
|
|
515
|
-
|
|
516
|
-
self.houses_names_list = list(get_args(Houses))
|
|
517
|
-
|
|
518
|
-
# Deprecated
|
|
519
|
-
self._houses_list = [
|
|
520
|
-
self.first_house,
|
|
521
|
-
self.second_house,
|
|
522
|
-
self.third_house,
|
|
523
|
-
self.fourth_house,
|
|
524
|
-
self.fifth_house,
|
|
525
|
-
self.sixth_house,
|
|
526
|
-
self.seventh_house,
|
|
527
|
-
self.eighth_house,
|
|
528
|
-
self.ninth_house,
|
|
529
|
-
self.tenth_house,
|
|
530
|
-
self.eleventh_house,
|
|
531
|
-
self.twelfth_house,
|
|
532
|
-
]
|
|
533
|
-
|
|
534
|
-
# AxialCusps
|
|
535
|
-
point_type: PointType = "AxialCusps"
|
|
536
|
-
|
|
537
|
-
# Calculate ascendant and medium coeli
|
|
538
|
-
self.ascendant = get_kerykeion_point_from_degree(_ascmc[0], "Ascendant", point_type=point_type)
|
|
539
|
-
self.medium_coeli = get_kerykeion_point_from_degree(_ascmc[1], "Medium_Coeli", point_type=point_type)
|
|
540
|
-
# For descendant and imum coeli there exist no Swiss Ephemeris library calculation function,
|
|
541
|
-
# but they are simply opposite the the ascendant and medium coeli
|
|
542
|
-
dsc_deg = math.fmod(_ascmc[0] + 180, 360)
|
|
543
|
-
ic_deg = math.fmod(_ascmc[1] + 180, 360)
|
|
544
|
-
self.descendant = get_kerykeion_point_from_degree(dsc_deg, "Descendant", point_type=point_type)
|
|
545
|
-
self.imum_coeli = get_kerykeion_point_from_degree(ic_deg, "Imum_Coeli", point_type=point_type)
|
|
546
|
-
|
|
547
|
-
def _initialize_planets(self) -> None:
|
|
548
|
-
"""Defines body positon in signs and information and
|
|
549
|
-
stores them in dictionaries"""
|
|
550
|
-
|
|
551
|
-
point_type: PointType = "Planet"
|
|
552
|
-
|
|
553
|
-
sun_deg = swe.calc_ut(self.julian_day, 0, self._iflag)[0][0]
|
|
554
|
-
moon_deg = swe.calc_ut(self.julian_day, 1, self._iflag)[0][0]
|
|
555
|
-
mercury_deg = swe.calc_ut(self.julian_day, 2, self._iflag)[0][0]
|
|
556
|
-
venus_deg = swe.calc_ut(self.julian_day, 3, self._iflag)[0][0]
|
|
557
|
-
mars_deg = swe.calc_ut(self.julian_day, 4, self._iflag)[0][0]
|
|
558
|
-
jupiter_deg = swe.calc_ut(self.julian_day, 5, self._iflag)[0][0]
|
|
559
|
-
saturn_deg = swe.calc_ut(self.julian_day, 6, self._iflag)[0][0]
|
|
560
|
-
uranus_deg = swe.calc_ut(self.julian_day, 7, self._iflag)[0][0]
|
|
561
|
-
neptune_deg = swe.calc_ut(self.julian_day, 8, self._iflag)[0][0]
|
|
562
|
-
pluto_deg = swe.calc_ut(self.julian_day, 9, self._iflag)[0][0]
|
|
563
|
-
mean_node_deg = swe.calc_ut(self.julian_day, 10, self._iflag)[0][0]
|
|
564
|
-
true_node_deg = swe.calc_ut(self.julian_day, 11, self._iflag)[0][0]
|
|
565
|
-
# For south nodes there exist no Swiss Ephemeris library calculation function,
|
|
566
|
-
# but they are simply opposite the north node.
|
|
567
|
-
mean_south_node_deg = math.fmod(mean_node_deg + 180, 360)
|
|
568
|
-
true_south_node_deg = math.fmod(true_node_deg + 180, 360)
|
|
569
|
-
|
|
570
|
-
# AC/DC axis and MC/IC axis were already calculated previously...
|
|
571
|
-
|
|
572
|
-
self.sun = get_kerykeion_point_from_degree(sun_deg, "Sun", point_type=point_type)
|
|
573
|
-
self.moon = get_kerykeion_point_from_degree(moon_deg, "Moon", point_type=point_type)
|
|
574
|
-
self.mercury = get_kerykeion_point_from_degree(mercury_deg, "Mercury", point_type=point_type)
|
|
575
|
-
self.venus = get_kerykeion_point_from_degree(venus_deg, "Venus", point_type=point_type)
|
|
576
|
-
self.mars = get_kerykeion_point_from_degree(mars_deg, "Mars", point_type=point_type)
|
|
577
|
-
self.jupiter = get_kerykeion_point_from_degree(jupiter_deg, "Jupiter", point_type=point_type)
|
|
578
|
-
self.saturn = get_kerykeion_point_from_degree(saturn_deg, "Saturn", point_type=point_type)
|
|
579
|
-
self.uranus = get_kerykeion_point_from_degree(uranus_deg, "Uranus", point_type=point_type)
|
|
580
|
-
self.neptune = get_kerykeion_point_from_degree(neptune_deg, "Neptune", point_type=point_type)
|
|
581
|
-
self.pluto = get_kerykeion_point_from_degree(pluto_deg, "Pluto", point_type=point_type)
|
|
582
|
-
self.mean_node = get_kerykeion_point_from_degree(mean_node_deg, "Mean_Node", point_type=point_type)
|
|
583
|
-
self.true_node = get_kerykeion_point_from_degree(true_node_deg, "True_Node", point_type=point_type)
|
|
584
|
-
self.mean_south_node = get_kerykeion_point_from_degree(mean_south_node_deg, "Mean_South_Node", point_type=point_type)
|
|
585
|
-
self.true_south_node = get_kerykeion_point_from_degree(true_south_node_deg, "True_South_Node", point_type=point_type)
|
|
586
|
-
|
|
587
|
-
# Note that in whole-sign house systems ac/dc or mc/ic axes may not align with house cusps.
|
|
588
|
-
# Therefore, for the axes we need to calculate house positions explicitly too.
|
|
589
|
-
self.ascendant.house = get_planet_house(self.ascendant.abs_pos, self._houses_degree_ut)
|
|
590
|
-
self.descendant.house = get_planet_house(self.descendant.abs_pos, self._houses_degree_ut)
|
|
591
|
-
self.medium_coeli.house = get_planet_house(self.medium_coeli.abs_pos, self._houses_degree_ut)
|
|
592
|
-
self.imum_coeli.house = get_planet_house(self.imum_coeli.abs_pos, self._houses_degree_ut)
|
|
593
|
-
|
|
594
|
-
self.sun.house = get_planet_house(sun_deg, self._houses_degree_ut)
|
|
595
|
-
self.moon.house = get_planet_house(moon_deg, self._houses_degree_ut)
|
|
596
|
-
self.mercury.house = get_planet_house(mercury_deg, self._houses_degree_ut)
|
|
597
|
-
self.venus.house = get_planet_house(venus_deg, self._houses_degree_ut)
|
|
598
|
-
self.mars.house = get_planet_house(mars_deg, self._houses_degree_ut)
|
|
599
|
-
self.jupiter.house = get_planet_house(jupiter_deg, self._houses_degree_ut)
|
|
600
|
-
self.saturn.house = get_planet_house(saturn_deg, self._houses_degree_ut)
|
|
601
|
-
self.uranus.house = get_planet_house(uranus_deg, self._houses_degree_ut)
|
|
602
|
-
self.neptune.house = get_planet_house(neptune_deg, self._houses_degree_ut)
|
|
603
|
-
self.pluto.house = get_planet_house(pluto_deg, self._houses_degree_ut)
|
|
604
|
-
self.mean_node.house = get_planet_house(mean_node_deg, self._houses_degree_ut)
|
|
605
|
-
self.true_node.house = get_planet_house(true_node_deg, self._houses_degree_ut)
|
|
606
|
-
self.mean_south_node.house = get_planet_house(mean_south_node_deg, self._houses_degree_ut)
|
|
607
|
-
self.true_south_node.house = get_planet_house(true_south_node_deg, self._houses_degree_ut)
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
# Deprecated
|
|
611
|
-
planets_list = [
|
|
612
|
-
self.sun,
|
|
613
|
-
self.moon,
|
|
614
|
-
self.mercury,
|
|
615
|
-
self.venus,
|
|
616
|
-
self.mars,
|
|
617
|
-
self.jupiter,
|
|
618
|
-
self.saturn,
|
|
619
|
-
self.uranus,
|
|
620
|
-
self.neptune,
|
|
621
|
-
self.pluto,
|
|
622
|
-
self.mean_node,
|
|
623
|
-
self.true_node,
|
|
624
|
-
self.mean_south_node,
|
|
625
|
-
self.true_south_node,
|
|
626
|
-
]
|
|
627
|
-
|
|
628
|
-
if not self.disable_chiron_and_lilith:
|
|
629
|
-
chiron_deg = swe.calc_ut(self.julian_day, 15, self._iflag)[0][0]
|
|
630
|
-
mean_lilith_deg = swe.calc_ut(self.julian_day, 12, self._iflag)[0][0]
|
|
631
|
-
|
|
632
|
-
self.chiron = get_kerykeion_point_from_degree(chiron_deg, "Chiron", point_type=point_type)
|
|
633
|
-
self.mean_lilith = get_kerykeion_point_from_degree(mean_lilith_deg, "Mean_Lilith", point_type=point_type)
|
|
634
|
-
|
|
635
|
-
self.chiron.house = get_planet_house(chiron_deg, self._houses_degree_ut)
|
|
636
|
-
self.mean_lilith.house = get_planet_house(mean_lilith_deg, self._houses_degree_ut)
|
|
637
|
-
|
|
638
|
-
# Deprecated
|
|
639
|
-
planets_list.append(self.chiron)
|
|
640
|
-
planets_list.append(self.mean_lilith)
|
|
641
|
-
|
|
642
|
-
else:
|
|
643
|
-
self.chiron = None
|
|
644
|
-
self.mean_lilith = None
|
|
645
|
-
|
|
646
|
-
# FIXME: Update after removing planets_list
|
|
647
|
-
self.planets_names_list = [planet["name"] for planet in planets_list]
|
|
648
|
-
self.axial_cusps_names_list = [
|
|
649
|
-
axis["name"] for axis in [self.ascendant, self.descendant, self.medium_coeli, self.imum_coeli]
|
|
650
|
-
]
|
|
651
|
-
|
|
652
|
-
# Check in retrograde or not:
|
|
653
|
-
for planet in planets_list:
|
|
654
|
-
planet_number = get_number_from_name(planet["name"])
|
|
655
|
-
|
|
656
|
-
# Swiss ephemeris library does not offer calculation of direction of south nodes.
|
|
657
|
-
# But south nodes have same direction as north nodes. We can use those to calculate direction.
|
|
658
|
-
if planet_number == 1000: # Number of Mean South Node
|
|
659
|
-
planet_number = 10 # Number of Mean North Node
|
|
660
|
-
elif planet_number == 1100: # Number of True South Node
|
|
661
|
-
planet_number = 11 # Number of True North Node
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
if swe.calc_ut(self.julian_day, planet_number, self._iflag)[0][3] < 0:
|
|
665
|
-
planet["retrograde"] = True
|
|
666
|
-
else:
|
|
667
|
-
planet["retrograde"] = False
|
|
668
|
-
|
|
669
|
-
# AC/DC and MC/IC axes are never retrograde. For consistency, set them to be not retrograde.
|
|
670
|
-
self.ascendant.retrograde = False
|
|
671
|
-
self.descendant.retrograde = False
|
|
672
|
-
self.medium_coeli.retrograde = False
|
|
673
|
-
self.imum_coeli.retrograde = False
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
def json(self, dump=False, destination_folder: Union[str, None] = None, indent: Union[int, None] = None) -> str:
|
|
677
|
-
"""
|
|
678
|
-
Dumps the Kerykeion object to a json string foramt,
|
|
679
|
-
if dump=True also dumps to file located in destination
|
|
680
|
-
or the home folder.
|
|
681
|
-
"""
|
|
682
|
-
|
|
683
|
-
KrData = AstrologicalSubjectModel(**self.__dict__)
|
|
684
|
-
json_string = KrData.model_dump_json(exclude_none=True, indent=indent)
|
|
685
|
-
|
|
686
|
-
if dump:
|
|
687
|
-
if destination_folder:
|
|
688
|
-
destination_path = Path(destination_folder)
|
|
689
|
-
json_path = destination_path / f"{self.name}_kerykeion.json"
|
|
690
|
-
|
|
691
|
-
else:
|
|
692
|
-
json_path = self.json_dir / f"{self.name}_kerykeion.json"
|
|
693
|
-
|
|
694
|
-
with open(json_path, "w", encoding="utf-8") as file:
|
|
695
|
-
file.write(json_string)
|
|
696
|
-
logging.info(f"JSON file dumped in {json_path}.")
|
|
697
|
-
|
|
698
|
-
return json_string
|
|
699
|
-
|
|
700
|
-
def model(self) -> AstrologicalSubjectModel:
|
|
701
|
-
"""
|
|
702
|
-
Creates a Pydantic model of the Kerykeion object.
|
|
703
|
-
"""
|
|
704
|
-
|
|
705
|
-
return AstrologicalSubjectModel(**self.__dict__)
|
|
706
|
-
|
|
707
|
-
@cached_property
|
|
708
|
-
def utc_time(self) -> float:
|
|
709
|
-
"""
|
|
710
|
-
Deprecated property, use iso_formatted_utc_datetime instead, will be removed in the future.
|
|
711
|
-
Returns the UTC time as a float.
|
|
712
|
-
"""
|
|
713
|
-
dt = datetime.fromisoformat(self.iso_formatted_utc_datetime)
|
|
714
|
-
|
|
715
|
-
# Extract the hours, minutes, and seconds
|
|
716
|
-
hours = dt.hour
|
|
717
|
-
minutes = dt.minute
|
|
718
|
-
seconds = dt.second + dt.microsecond / 1_000_000
|
|
719
|
-
|
|
720
|
-
# Convert time to float hours
|
|
721
|
-
float_time = hours + minutes / 60 + seconds / 3600
|
|
722
|
-
|
|
723
|
-
return float_time
|
|
724
|
-
|
|
725
|
-
@cached_property
|
|
726
|
-
def local_time(self) -> float:
|
|
727
|
-
"""
|
|
728
|
-
Deprecated property, use iso_formatted_local_datetime instead, will be removed in the future.
|
|
729
|
-
Returns the local time as a float.
|
|
730
|
-
"""
|
|
731
|
-
dt = datetime.fromisoformat(self.iso_formatted_local_datetime)
|
|
732
|
-
|
|
733
|
-
# Extract the hours, minutes, and seconds
|
|
734
|
-
hours = dt.hour
|
|
735
|
-
minutes = dt.minute
|
|
736
|
-
seconds = dt.second + dt.microsecond / 1_000_000
|
|
737
|
-
|
|
738
|
-
# Convert time to float hours
|
|
739
|
-
float_time = hours + minutes / 60 + seconds / 3600
|
|
740
|
-
|
|
741
|
-
return float_time
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
@staticmethod
|
|
745
|
-
def get_from_iso_utc_time(
|
|
746
|
-
name: str,
|
|
747
|
-
iso_utc_time: str,
|
|
748
|
-
city: str = "Greenwich",
|
|
749
|
-
nation: str = "GB",
|
|
750
|
-
tz_str: str = "Etc/GMT",
|
|
751
|
-
online: bool = False,
|
|
752
|
-
lng: Union[int, float] = 0,
|
|
753
|
-
lat: Union[int, float] = 51.5074,
|
|
754
|
-
geonames_username: str = DEFAULT_GEONAMES_USERNAME,
|
|
755
|
-
zodiac_type: ZodiacType = DEFAULT_ZODIAC_TYPE,
|
|
756
|
-
disable_chiron_and_lilith: bool = False,
|
|
757
|
-
sidereal_mode: Union[SiderealMode, None] = None,
|
|
758
|
-
houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER,
|
|
759
|
-
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE
|
|
760
|
-
|
|
761
|
-
) -> "AstrologicalSubject":
|
|
762
|
-
"""
|
|
763
|
-
Creates an AstrologicalSubject object from an iso formatted UTC time.
|
|
764
|
-
This method is offline by default, set online=True to fetch the timezone and coordinates from geonames.
|
|
765
|
-
|
|
766
|
-
Args:
|
|
767
|
-
- name (str): The name of the subject.
|
|
768
|
-
- iso_utc_time (str): The iso formatted UTC time.
|
|
769
|
-
- city (str, optional): City or location of birth. Defaults to "Greenwich".
|
|
770
|
-
- nation (str, optional): Nation of birth. Defaults to "GB".
|
|
771
|
-
- tz_str (str, optional): Timezone of the birth location. Defaults to "Etc/GMT".
|
|
772
|
-
- online (bool, optional): Sets if you want to use the online mode, which fetches the timezone and coordinates from geonames.
|
|
773
|
-
If you already have the coordinates and timezone, set this to False. Defaults to False.
|
|
774
|
-
- lng (Union[int, float], optional): Longitude of the birth location. Defaults to 0 (Greenwich, London).
|
|
775
|
-
- lat (Union[int, float], optional): Latitude of the birth location. Defaults to 51.5074 (Greenwich, London).
|
|
776
|
-
- geonames_username (str, optional): The username for the geonames API. Note: Change this to your own username to avoid rate limits!
|
|
777
|
-
You can get one for free here: https://www.geonames.org/login
|
|
778
|
-
- zodiac_type (ZodiacType, optional): The zodiac type to use. Defaults to "Tropic".
|
|
779
|
-
- disable_chiron_and_lilith: boolean representing if Chiron and Lilith should be disabled. Default is False.
|
|
780
|
-
Chiron calculation can create some issues with the Swiss Ephemeris when the date is too far in the past.
|
|
781
|
-
- sidereal_mode (SiderealMode, optional): Also known as Ayanamsa.
|
|
782
|
-
The mode to use for the sidereal zodiac, according to the Swiss Ephemeris.
|
|
783
|
-
Defaults to None.
|
|
784
|
-
Available modes are visible in the SiderealMode Literal.
|
|
785
|
-
- houses_system_identifier (HousesSystemIdentifier, optional): The system to use for the calculation of the houses.
|
|
786
|
-
Defaults to "P" (Placidus).
|
|
787
|
-
Available systems are visible in the HousesSystemIdentifier Literal.
|
|
788
|
-
- perspective_type (PerspectiveType, optional): The perspective to use for the calculation of the chart.
|
|
789
|
-
Defaults to "Apparent Geocentric".
|
|
790
|
-
|
|
791
|
-
Returns:
|
|
792
|
-
- AstrologicalSubject: The AstrologicalSubject object.
|
|
793
|
-
"""
|
|
794
|
-
dt = datetime.fromisoformat(iso_utc_time)
|
|
795
|
-
|
|
796
|
-
if online == True:
|
|
797
|
-
if geonames_username == DEFAULT_GEONAMES_USERNAME:
|
|
798
|
-
logging.warning(GEONAMES_DEFAULT_USERNAME_WARNING)
|
|
799
|
-
|
|
800
|
-
geonames = FetchGeonames(
|
|
801
|
-
city,
|
|
802
|
-
nation,
|
|
803
|
-
username=geonames_username,
|
|
804
|
-
)
|
|
805
|
-
|
|
806
|
-
city_data: dict[str, str] = geonames.get_serialized_data()
|
|
807
|
-
lng = float(city_data["lng"])
|
|
808
|
-
lat = float(city_data["lat"])
|
|
809
|
-
|
|
810
|
-
subject = AstrologicalSubject(
|
|
811
|
-
name=name,
|
|
812
|
-
year=dt.year,
|
|
813
|
-
month=dt.month,
|
|
814
|
-
day=dt.day,
|
|
815
|
-
hour=dt.hour,
|
|
816
|
-
minute=dt.minute,
|
|
817
|
-
city=city,
|
|
818
|
-
nation=city,
|
|
819
|
-
lng=lng,
|
|
820
|
-
lat=lat,
|
|
821
|
-
tz_str=tz_str,
|
|
822
|
-
online=False,
|
|
823
|
-
geonames_username=geonames_username,
|
|
824
|
-
zodiac_type=zodiac_type,
|
|
825
|
-
sidereal_mode=sidereal_mode,
|
|
826
|
-
houses_system_identifier=houses_system_identifier,
|
|
827
|
-
perspective_type=perspective_type,
|
|
828
|
-
disable_chiron_and_lilith=disable_chiron_and_lilith
|
|
829
|
-
)
|
|
830
|
-
|
|
831
|
-
return subject
|
|
832
|
-
|
|
833
|
-
if __name__ == "__main__":
|
|
834
|
-
import json
|
|
835
|
-
from kerykeion.utilities import setup_logging
|
|
836
|
-
|
|
837
|
-
setup_logging(level="debug")
|
|
838
|
-
|
|
839
|
-
# With Chiron enabled
|
|
840
|
-
johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", zodiac_type=None)
|
|
841
|
-
print(json.loads(johnny.json(dump=True)))
|