kerykeion 4.12.8__tar.gz → 4.13.0__tar.gz
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-4.12.8 → kerykeion-4.13.0}/PKG-INFO +1 -1
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/__init__.py +1 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/astrological_subject.py +21 -11
- kerykeion-4.13.0/kerykeion/ephemeris_data.py +174 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/kr_types/kr_models.py +5 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/pyproject.toml +1 -1
- {kerykeion-4.12.8 → kerykeion-4.13.0}/LICENSE +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/README.md +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/aspects/__init__.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/aspects/aspects_utils.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/aspects/natal_aspects.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/aspects/synastry_aspects.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/charts/__init__.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/charts/charts_utils.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/charts/kerykeion_chart_svg.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/charts/templates/chart.xml +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/enums.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/fetch_geonames.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/kr_types/__init__.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/kr_types/chart_types.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/kr_types/kerykeion_exception.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/kr_types/kr_literals.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/kr_types/settings_models.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/relationship_score.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/report.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/settings/__init__.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/settings/kerykeion_settings.py +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/settings/kr.config.json +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/sweph/README.md +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/sweph/seas_18.se1 +0 -0
- {kerykeion-4.12.8 → kerykeion-4.13.0}/kerykeion/utilities.py +0 -0
|
@@ -87,6 +87,9 @@ class AstrologicalSubject:
|
|
|
87
87
|
- perspective_type (PerspectiveType, optional): The perspective to use for the calculation of the chart.
|
|
88
88
|
Defaults to "Apparent Geocentric".
|
|
89
89
|
Available perspectives are visible in the PerspectiveType Literal.
|
|
90
|
+
- is_dst (Union[None, bool], optional): Specify if the time is in DST. Defaults to None.
|
|
91
|
+
By default (None), the library will try to guess if the time is in DST or not and raise an AmbiguousTimeError
|
|
92
|
+
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.
|
|
90
93
|
"""
|
|
91
94
|
|
|
92
95
|
# Defined by the user
|
|
@@ -108,6 +111,7 @@ class AstrologicalSubject:
|
|
|
108
111
|
houses_system_identifier: HousesSystemIdentifier
|
|
109
112
|
houses_system_name: str
|
|
110
113
|
perspective_type: PerspectiveType
|
|
114
|
+
is_dst: Union[None, bool]
|
|
111
115
|
|
|
112
116
|
# Generated internally
|
|
113
117
|
city_data: dict[str, str]
|
|
@@ -170,7 +174,8 @@ class AstrologicalSubject:
|
|
|
170
174
|
disable_chiron: bool = False,
|
|
171
175
|
sidereal_mode: Union[SiderealMode, None] = None,
|
|
172
176
|
houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER,
|
|
173
|
-
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE
|
|
177
|
+
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE,
|
|
178
|
+
is_dst: Union[None, bool] = None
|
|
174
179
|
) -> None:
|
|
175
180
|
logging.debug("Starting Kerykeion")
|
|
176
181
|
|
|
@@ -193,6 +198,7 @@ class AstrologicalSubject:
|
|
|
193
198
|
self.sidereal_mode = sidereal_mode
|
|
194
199
|
self.houses_system_identifier = houses_system_identifier
|
|
195
200
|
self.perspective_type = perspective_type
|
|
201
|
+
self.is_dst = is_dst
|
|
196
202
|
|
|
197
203
|
#---------------#
|
|
198
204
|
# General setup #
|
|
@@ -212,11 +218,11 @@ class AstrologicalSubject:
|
|
|
212
218
|
self.nation = "GB"
|
|
213
219
|
logging.info("No nation specified, using GB as default")
|
|
214
220
|
|
|
215
|
-
if not self.lat:
|
|
221
|
+
if not self.lat and not self.online:
|
|
216
222
|
self.lat = 51.5074
|
|
217
223
|
logging.info("No latitude specified, using London as default")
|
|
218
224
|
|
|
219
|
-
if not self.lng:
|
|
225
|
+
if not self.lng and not self.online:
|
|
220
226
|
self.lng = 0
|
|
221
227
|
logging.info("No longitude specified, using London as default")
|
|
222
228
|
|
|
@@ -244,6 +250,7 @@ class AstrologicalSubject:
|
|
|
244
250
|
elif self.perspective_type == "Topocentric":
|
|
245
251
|
self._iflag += swe.FLG_TOPOCTR
|
|
246
252
|
# geopos_is_set, for topocentric
|
|
253
|
+
self._fetch_and_set_tz_and_coordinates_from_geonames()
|
|
247
254
|
swe.set_topo(self.lng, self.lat, 0)
|
|
248
255
|
# <--- Chart Perspective check and setup
|
|
249
256
|
|
|
@@ -279,17 +286,22 @@ class AstrologicalSubject:
|
|
|
279
286
|
#------------------------#
|
|
280
287
|
# Start the calculations #
|
|
281
288
|
#------------------------#
|
|
282
|
-
|
|
283
|
-
self.lat = check_and_adjust_polar_latitude(self.lat)
|
|
284
289
|
|
|
285
290
|
# UTC, julian day and local time setup --->
|
|
286
|
-
if (self.online) and (not self.tz_str):
|
|
287
|
-
self.
|
|
291
|
+
if (self.online) and (not self.tz_str) and (not self.lat) and (not self.lng):
|
|
292
|
+
self._fetch_and_set_tz_and_coordinates_from_geonames()
|
|
293
|
+
|
|
294
|
+
self.lat = check_and_adjust_polar_latitude(self.lat)
|
|
288
295
|
|
|
289
296
|
# Local time to UTC
|
|
290
297
|
local_time = pytz.timezone(self.tz_str)
|
|
291
298
|
naive_datetime = datetime(self.year, self.month, self.day, self.hour, self.minute, 0)
|
|
292
|
-
|
|
299
|
+
|
|
300
|
+
try:
|
|
301
|
+
local_datetime = local_time.localize(naive_datetime, is_dst=self.is_dst)
|
|
302
|
+
except pytz.exceptions.AmbiguousTimeError:
|
|
303
|
+
raise KerykeionException("Ambiguous time! Please specify if the time is in DST or not with the is_dst argument.")
|
|
304
|
+
|
|
293
305
|
utc_object = local_datetime.astimezone(pytz.utc)
|
|
294
306
|
self.iso_formatted_utc_datetime = utc_object.isoformat()
|
|
295
307
|
|
|
@@ -323,7 +335,7 @@ class AstrologicalSubject:
|
|
|
323
335
|
def get(self, item, default=None):
|
|
324
336
|
return getattr(self, item, default)
|
|
325
337
|
|
|
326
|
-
def
|
|
338
|
+
def _fetch_and_set_tz_and_coordinates_from_geonames(self) -> None:
|
|
327
339
|
"""Gets the nearest time zone for the calculation"""
|
|
328
340
|
logging.info("Fetching timezone/coordinates from geonames")
|
|
329
341
|
|
|
@@ -347,8 +359,6 @@ class AstrologicalSubject:
|
|
|
347
359
|
self.lat = float(self.city_data["lat"])
|
|
348
360
|
self.tz_str = self.city_data["timezonestr"]
|
|
349
361
|
|
|
350
|
-
self.lat = check_and_adjust_polar_latitude(self.lat)
|
|
351
|
-
|
|
352
362
|
def _houses(self) -> None:
|
|
353
363
|
"""
|
|
354
364
|
Calculate positions and store them in dictionaries
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
from kerykeion import AstrologicalSubject
|
|
2
|
+
from kerykeion.astrological_subject import DEFAULT_HOUSES_SYSTEM_IDENTIFIER, DEFAULT_PERSPECTIVE_TYPE, DEFAULT_ZODIAC_TYPE
|
|
3
|
+
from kerykeion.kr_types import EphemerisDictModel
|
|
4
|
+
from kerykeion.kr_types import SiderealMode, HousesSystemIdentifier, PerspectiveType, ZodiacType
|
|
5
|
+
from datetime import datetime, timedelta
|
|
6
|
+
from typing import Literal
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EphemerisDataFactory:
|
|
11
|
+
"""
|
|
12
|
+
This class is used to generate ephemeris data for a given date range.
|
|
13
|
+
|
|
14
|
+
Parameters:
|
|
15
|
+
- start_datetime: datetime object representing the start date and time.
|
|
16
|
+
- end_datetime: datetime object representing the end date and time.
|
|
17
|
+
- step_type: string representing the step type. It can be "days", "hours", or "minutes". Default is "days".
|
|
18
|
+
- step: integer representing the step value. Default is 1.
|
|
19
|
+
- lat: float representing the latitude. Default is 51.4769 (Greenwich).
|
|
20
|
+
- lng: float representing the longitude. Default is 0.0005 (Greenwich).
|
|
21
|
+
- tz_str: string representing the timezone. Default is "Etc/UTC".
|
|
22
|
+
- is_dst: boolean representing if daylight saving time is active. Default is False.
|
|
23
|
+
- disable_chiron: boolean representing if Chiron should be disabled. Default is False.
|
|
24
|
+
- zodiac_type: ZodiacType object representing the zodiac type. Default is DEFAULT_ZODIAC_TYPE.
|
|
25
|
+
- sidereal_mode: SiderealMode object representing the sidereal mode. Default is None.
|
|
26
|
+
- houses_system_identifier: HousesSystemIdentifier object representing the houses system identifier. Default is DEFAULT_HOUSES_SYSTEM_IDENTIFIER.
|
|
27
|
+
- perspective_type: PerspectiveType object representing the perspective type. Default is DEFAULT_PERSPECTIVE_TYPE.
|
|
28
|
+
- max_days: integer representing the maximum number of days.
|
|
29
|
+
Set it to None to disable the check. Default is 730.
|
|
30
|
+
- max_hours: integer representing the maximum number of hours.
|
|
31
|
+
Set it to None to disable the check. Default is 8760.
|
|
32
|
+
- max_minutes: integer representing the maximum number of minutes.
|
|
33
|
+
Set it to None to disable the check. Default is 525600.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
- ValueError: if the step type is invalid.
|
|
37
|
+
- ValueError: if the number of days, hours, or minutes is greater than the maximum allowed.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
start_datetime: datetime,
|
|
43
|
+
end_datetime: datetime,
|
|
44
|
+
step_type: Literal["days", "hours", "minutes"] = "days",
|
|
45
|
+
step: int = 1,
|
|
46
|
+
lat: float = 51.4769,
|
|
47
|
+
lng: float = 0.0005,
|
|
48
|
+
tz_str: str = "Etc/UTC",
|
|
49
|
+
is_dst: bool = False,
|
|
50
|
+
disable_chiron: bool = False,
|
|
51
|
+
zodiac_type: ZodiacType = DEFAULT_ZODIAC_TYPE,
|
|
52
|
+
sidereal_mode: SiderealMode | None = None,
|
|
53
|
+
houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER,
|
|
54
|
+
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE,
|
|
55
|
+
max_days: int = 730,
|
|
56
|
+
max_hours: int = 8760,
|
|
57
|
+
max_minutes: int = 525600,
|
|
58
|
+
):
|
|
59
|
+
self.start_datetime = start_datetime
|
|
60
|
+
self.end_datetime = end_datetime
|
|
61
|
+
self.step_type = step_type
|
|
62
|
+
self.step = step
|
|
63
|
+
self.lat = lat
|
|
64
|
+
self.lng = lng
|
|
65
|
+
self.tz_str = tz_str
|
|
66
|
+
self.is_dst = is_dst
|
|
67
|
+
self.disable_chiron = disable_chiron
|
|
68
|
+
self.zodiac_type = zodiac_type
|
|
69
|
+
self.sidereal_mode = sidereal_mode
|
|
70
|
+
self.houses_system_identifier = houses_system_identifier
|
|
71
|
+
self.perspective_type = perspective_type
|
|
72
|
+
self.max_days = max_days
|
|
73
|
+
self.max_hours = max_hours
|
|
74
|
+
self.max_minutes = max_minutes
|
|
75
|
+
|
|
76
|
+
self.dates_list = []
|
|
77
|
+
if self.step_type == "days":
|
|
78
|
+
self.dates_list = [self.start_datetime + timedelta(days=i) for i in range((self.end_datetime - self.start_datetime).days)]
|
|
79
|
+
if max_days and (len(self.dates_list) > max_days):
|
|
80
|
+
raise ValueError(f"Too many days: {len(self.dates_list)} > {self.max_days}. To prevent this error, set max_days to a higher value or reduce the date range.")
|
|
81
|
+
|
|
82
|
+
elif self.step_type == "hours":
|
|
83
|
+
self.dates_list = [self.start_datetime + timedelta(hours=i) for i in range((self.end_datetime - self.start_datetime).days * 24)]
|
|
84
|
+
if max_hours and (len(self.dates_list) > max_hours):
|
|
85
|
+
raise ValueError(f"Too many hours: {len(self.dates_list)} > {self.max_hours}. To prevent this error, set max_hours to a higher value or reduce the date range.")
|
|
86
|
+
|
|
87
|
+
elif self.step_type == "minutes":
|
|
88
|
+
self.dates_list = [self.start_datetime + timedelta(minutes=i) for i in range((self.end_datetime - self.start_datetime).days * 24 * 60)]
|
|
89
|
+
if max_minutes and (len(self.dates_list) > max_minutes):
|
|
90
|
+
raise ValueError(f"Too many minutes: {len(self.dates_list)} > {self.max_minutes}. To prevent this error, set max_minutes to a higher value or reduce the date range.")
|
|
91
|
+
|
|
92
|
+
else:
|
|
93
|
+
raise ValueError(f"Invalid step type: {self.step_type}")
|
|
94
|
+
|
|
95
|
+
if not self.dates_list:
|
|
96
|
+
raise ValueError("No dates found. Check the date range and step values.")
|
|
97
|
+
|
|
98
|
+
if len(self.dates_list) > 1000:
|
|
99
|
+
logging.warning(f"Large number of dates: {len(self.dates_list)}. The calculation may take a while.")
|
|
100
|
+
|
|
101
|
+
def get_ephemeris_data(self) -> list:
|
|
102
|
+
"""
|
|
103
|
+
Generate ephemeris data for the specified date range.
|
|
104
|
+
The data is structured as a list of dictionaries, where each dictionary contains the date, planets, and houses data.
|
|
105
|
+
Eg. [{"date": "2020-01-01T00:00:00", "planets": [{...}, {...}, ...], "houses": [{...}, {...}, ...]}, ...]
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
- as_model: boolean representing if the ephemeris data should be returned as model instances. Default is False.
|
|
109
|
+
- as_dict: boolean representing if the ephemeris data should be returned as dictionaries. Default is False.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
- list of dictionaries representing the ephemeris data.
|
|
113
|
+
"""
|
|
114
|
+
ephemeris_data_list = []
|
|
115
|
+
for date in self.dates_list:
|
|
116
|
+
subject = AstrologicalSubject(
|
|
117
|
+
year=date.year,
|
|
118
|
+
month=date.month,
|
|
119
|
+
day=date.day,
|
|
120
|
+
hour=date.hour,
|
|
121
|
+
minute=date.minute,
|
|
122
|
+
lng=self.lng,
|
|
123
|
+
lat=self.lat,
|
|
124
|
+
tz_str=self.tz_str,
|
|
125
|
+
city="Placeholder",
|
|
126
|
+
nation="Placeholder",
|
|
127
|
+
online=False,
|
|
128
|
+
disable_chiron=self.disable_chiron,
|
|
129
|
+
zodiac_type=self.zodiac_type,
|
|
130
|
+
sidereal_mode=self.sidereal_mode,
|
|
131
|
+
houses_system_identifier=self.houses_system_identifier,
|
|
132
|
+
perspective_type=self.perspective_type,
|
|
133
|
+
is_dst=self.is_dst,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
ephemeris_data_list.append({"date": date.isoformat(), "planets": subject.planets_list, "houses": subject.houses_list})
|
|
137
|
+
|
|
138
|
+
return ephemeris_data_list
|
|
139
|
+
|
|
140
|
+
def get_ephemeris_data_as_model(self) -> list[EphemerisDictModel]:
|
|
141
|
+
"""
|
|
142
|
+
Generate ephemeris data as model instances for the specified date range.
|
|
143
|
+
The data is structured as a list of EphemerisDictModel instances.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
- list of EphemerisDictModel instances representing the ephemeris data.
|
|
147
|
+
"""
|
|
148
|
+
return [EphemerisDictModel(**data) for data in self.get_ephemeris_data()]
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if "__main__" == __name__:
|
|
152
|
+
start_date = datetime.fromisoformat("2020-01-01")
|
|
153
|
+
end_date = datetime.fromisoformat("2020-01-03")
|
|
154
|
+
|
|
155
|
+
factory = EphemerisDataFactory(
|
|
156
|
+
start_datetime=start_date,
|
|
157
|
+
end_datetime=end_date,
|
|
158
|
+
step_type="minutes",
|
|
159
|
+
step=1,
|
|
160
|
+
lat=37.9838,
|
|
161
|
+
lng=23.7275,
|
|
162
|
+
tz_str="Europe/Athens",
|
|
163
|
+
is_dst=False,
|
|
164
|
+
max_hours=None,
|
|
165
|
+
max_minutes=None,
|
|
166
|
+
max_days=None,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
ephemeris_data = factory.get_ephemeris_data_as_model()
|
|
170
|
+
print(ephemeris_data[0])
|
|
171
|
+
print(len(ephemeris_data))
|
|
172
|
+
|
|
173
|
+
for ephe in ephemeris_data:
|
|
174
|
+
print(ephe.planets[0]["abs_pos"])
|
|
@@ -120,6 +120,11 @@ class AstrologicalSubjectModel(SubscriptableBaseModel):
|
|
|
120
120
|
# planets_degrees_ut: list[float]
|
|
121
121
|
# houses_degree_ut: list[float]
|
|
122
122
|
|
|
123
|
+
class EphemerisDictModel(BaseModel):
|
|
124
|
+
date: str
|
|
125
|
+
planets: list[KerykeionPointModel]
|
|
126
|
+
houses: list[KerykeionPointModel]
|
|
127
|
+
|
|
123
128
|
if __name__ == "__main__":
|
|
124
129
|
from kerykeion.utilities import setup_logging
|
|
125
130
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|