kerykeion 5.1.5__py3-none-any.whl → 5.1.7__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/astrological_subject_factory.py +18 -14
- kerykeion/backword.py +44 -1
- kerykeion/charts/chart_drawer.py +15 -12
- kerykeion/ephemeris_data_factory.py +13 -4
- kerykeion/fetch_geonames.py +16 -11
- kerykeion/report.py +1 -2
- kerykeion/schemas/kr_literals.py +1 -1
- kerykeion/settings/kerykeion_settings.py +1 -1
- kerykeion/utilities.py +121 -121
- {kerykeion-5.1.5.dist-info → kerykeion-5.1.7.dist-info}/METADATA +3 -1
- {kerykeion-5.1.5.dist-info → kerykeion-5.1.7.dist-info}/RECORD +13 -13
- {kerykeion-5.1.5.dist-info → kerykeion-5.1.7.dist-info}/WHEEL +0 -0
- {kerykeion-5.1.5.dist-info → kerykeion-5.1.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -59,7 +59,8 @@ from kerykeion.utilities import (
|
|
|
59
59
|
check_and_adjust_polar_latitude,
|
|
60
60
|
calculate_moon_phase,
|
|
61
61
|
datetime_to_julian,
|
|
62
|
-
get_house_number
|
|
62
|
+
get_house_number,
|
|
63
|
+
normalize_zodiac_type,
|
|
63
64
|
)
|
|
64
65
|
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS
|
|
65
66
|
|
|
@@ -67,7 +68,7 @@ from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS
|
|
|
67
68
|
DEFAULT_GEONAMES_USERNAME = "century.boy"
|
|
68
69
|
DEFAULT_SIDEREAL_MODE: SiderealMode = "FAGAN_BRADLEY"
|
|
69
70
|
DEFAULT_HOUSES_SYSTEM_IDENTIFIER: HousesSystemIdentifier = "P"
|
|
70
|
-
DEFAULT_ZODIAC_TYPE: ZodiacType = "
|
|
71
|
+
DEFAULT_ZODIAC_TYPE: ZodiacType = "Tropical"
|
|
71
72
|
DEFAULT_PERSPECTIVE_TYPE: PerspectiveType = "Apparent Geocentric"
|
|
72
73
|
DEFAULT_GEONAMES_CACHE_EXPIRE_AFTER_DAYS = 30
|
|
73
74
|
|
|
@@ -148,8 +149,8 @@ class ChartConfiguration:
|
|
|
148
149
|
combinations.
|
|
149
150
|
|
|
150
151
|
Attributes:
|
|
151
|
-
zodiac_type (ZodiacType): The zodiac system to use ('
|
|
152
|
-
Defaults to '
|
|
152
|
+
zodiac_type (ZodiacType): The zodiac system to use ('Tropical' or 'Sidereal').
|
|
153
|
+
Defaults to 'Tropical'.
|
|
153
154
|
sidereal_mode (Optional[SiderealMode]): The sidereal calculation mode when using
|
|
154
155
|
sidereal zodiac. Only required/used when zodiac_type is 'Sidereal'.
|
|
155
156
|
Defaults to None (auto-set to FAGAN_BRADLEY for sidereal).
|
|
@@ -198,14 +199,17 @@ class ChartConfiguration:
|
|
|
198
199
|
- Logs informational message when setting default sidereal mode
|
|
199
200
|
"""
|
|
200
201
|
# Validate zodiac type
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
)
|
|
202
|
+
try:
|
|
203
|
+
normalized_zodiac_type = normalize_zodiac_type(self.zodiac_type)
|
|
204
|
+
except ValueError as exc:
|
|
205
|
+
raise KerykeionException(str(exc)) from exc
|
|
206
|
+
else:
|
|
207
|
+
if normalized_zodiac_type != self.zodiac_type:
|
|
208
|
+
self.zodiac_type = normalized_zodiac_type
|
|
205
209
|
|
|
206
210
|
# Validate sidereal mode settings
|
|
207
|
-
if self.sidereal_mode and self.zodiac_type == "
|
|
208
|
-
raise KerykeionException("You can't set a sidereal mode with a
|
|
211
|
+
if self.sidereal_mode and self.zodiac_type == "Tropical":
|
|
212
|
+
raise KerykeionException("You can't set a sidereal mode with a Tropical zodiac type!")
|
|
209
213
|
|
|
210
214
|
if self.zodiac_type == "Sidereal":
|
|
211
215
|
if not self.sidereal_mode:
|
|
@@ -475,8 +479,8 @@ class AstrologicalSubjectFactory:
|
|
|
475
479
|
online location lookup. Get one free at geonames.org.
|
|
476
480
|
online (bool, optional): Whether to fetch location data online. If False,
|
|
477
481
|
lng, lat, and tz_str must be provided. Defaults to True.
|
|
478
|
-
zodiac_type (ZodiacType, optional): Zodiac system - '
|
|
479
|
-
Defaults to '
|
|
482
|
+
zodiac_type (ZodiacType, optional): Zodiac system - 'Tropical' or 'Sidereal'.
|
|
483
|
+
Defaults to 'Tropical'.
|
|
480
484
|
sidereal_mode (SiderealMode, optional): Sidereal calculation mode (e.g.,
|
|
481
485
|
'FAGAN_BRADLEY', 'LAHIRI'). Only used with zodiac_type='Sidereal'.
|
|
482
486
|
houses_system_identifier (HousesSystemIdentifier, optional): House system
|
|
@@ -726,7 +730,7 @@ class AstrologicalSubjectFactory:
|
|
|
726
730
|
or as fallback. Defaults to 51.5074 (Greenwich).
|
|
727
731
|
geonames_username (str, optional): GeoNames API username. Required when
|
|
728
732
|
online=True. Defaults to DEFAULT_GEONAMES_USERNAME.
|
|
729
|
-
zodiac_type (ZodiacType, optional): Zodiac system. Defaults to '
|
|
733
|
+
zodiac_type (ZodiacType, optional): Zodiac system. Defaults to 'Tropical'.
|
|
730
734
|
sidereal_mode (SiderealMode, optional): Sidereal mode when zodiac_type
|
|
731
735
|
is 'Sidereal'. Defaults to None.
|
|
732
736
|
houses_system_identifier (HousesSystemIdentifier, optional): House system.
|
|
@@ -866,7 +870,7 @@ class AstrologicalSubjectFactory:
|
|
|
866
870
|
online (bool, optional): Whether to fetch location data online.
|
|
867
871
|
Defaults to True.
|
|
868
872
|
zodiac_type (ZodiacType, optional): Zodiac system to use.
|
|
869
|
-
Defaults to '
|
|
873
|
+
Defaults to 'Tropical'.
|
|
870
874
|
sidereal_mode (SiderealMode, optional): Sidereal calculation mode.
|
|
871
875
|
Only used when zodiac_type is 'Sidereal'. Defaults to None.
|
|
872
876
|
houses_system_identifier (HousesSystemIdentifier, optional): House
|
kerykeion/backword.py
CHANGED
|
@@ -36,6 +36,7 @@ from .chart_data_factory import ChartDataFactory
|
|
|
36
36
|
from .charts.chart_drawer import ChartDrawer
|
|
37
37
|
from .aspects import AspectsFactory
|
|
38
38
|
from .settings.config_constants import DEFAULT_ACTIVE_POINTS, DEFAULT_ACTIVE_ASPECTS
|
|
39
|
+
from .utilities import normalize_zodiac_type
|
|
39
40
|
from .schemas.kr_models import (
|
|
40
41
|
AstrologicalSubjectModel,
|
|
41
42
|
CompositeSubjectModel,
|
|
@@ -74,6 +75,42 @@ LEGACY_NODE_NAMES_MAP = {
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
|
|
78
|
+
def _normalize_zodiac_type_with_warning(zodiac_type: Optional[Union[str, ZodiacType]]) -> Optional[ZodiacType]:
|
|
79
|
+
"""Normalize legacy zodiac type values with deprecation warning.
|
|
80
|
+
|
|
81
|
+
Wraps the utilities.normalize_zodiac_type function and adds a deprecation
|
|
82
|
+
warning for legacy formats like "tropic" or case-insensitive variants.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
zodiac_type: Input zodiac type (may be legacy format)
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Normalized ZodiacType or None if input was None
|
|
89
|
+
"""
|
|
90
|
+
if zodiac_type is None:
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
zodiac_str = str(zodiac_type)
|
|
94
|
+
|
|
95
|
+
# Check if this is a legacy format (case-insensitive "tropic" or non-canonical case)
|
|
96
|
+
zodiac_lower = zodiac_str.lower()
|
|
97
|
+
if zodiac_lower in ("tropic", "tropical", "sidereal") and zodiac_str not in ("Tropical", "Sidereal"):
|
|
98
|
+
# Normalize using the utilities function
|
|
99
|
+
normalized = normalize_zodiac_type(zodiac_str)
|
|
100
|
+
|
|
101
|
+
# Emit deprecation warning for legacy usage
|
|
102
|
+
warnings.warn(
|
|
103
|
+
f"Zodiac type '{zodiac_str}' is deprecated in Kerykeion v5. "
|
|
104
|
+
f"Use '{normalized}' instead.",
|
|
105
|
+
DeprecationWarning,
|
|
106
|
+
stacklevel=4,
|
|
107
|
+
)
|
|
108
|
+
return normalized
|
|
109
|
+
|
|
110
|
+
# Already in correct format or will be normalized by utilities function
|
|
111
|
+
return cast(ZodiacType, normalize_zodiac_type(zodiac_str))
|
|
112
|
+
|
|
113
|
+
|
|
77
114
|
def _normalize_active_points(points: Optional[Iterable[Union[str, AstrologicalPoint]]]) -> Optional[List[AstrologicalPoint]]:
|
|
78
115
|
"""Best-effort normalization of legacy string active points list.
|
|
79
116
|
|
|
@@ -159,7 +196,10 @@ class AstrologicalSubject:
|
|
|
159
196
|
stacklevel=2,
|
|
160
197
|
)
|
|
161
198
|
|
|
199
|
+
# Normalize legacy zodiac type values
|
|
200
|
+
zodiac_type = _normalize_zodiac_type_with_warning(zodiac_type)
|
|
162
201
|
zodiac_type = DEFAULT_ZODIAC_TYPE if zodiac_type is None else zodiac_type
|
|
202
|
+
|
|
163
203
|
houses_system_identifier = (
|
|
164
204
|
DEFAULT_HOUSES_SYSTEM_IDENTIFIER if houses_system_identifier is None else houses_system_identifier
|
|
165
205
|
)
|
|
@@ -352,6 +392,9 @@ class AstrologicalSubject:
|
|
|
352
392
|
if online and resolved_geonames == DEFAULT_GEONAMES_USERNAME:
|
|
353
393
|
warnings.warn(GEONAMES_DEFAULT_USERNAME_WARNING, UserWarning, stacklevel=2)
|
|
354
394
|
|
|
395
|
+
# Normalize legacy zodiac type values
|
|
396
|
+
normalized_zodiac_type = _normalize_zodiac_type_with_warning(zodiac_type)
|
|
397
|
+
|
|
355
398
|
model = AstrologicalSubjectFactory.from_iso_utc_time(
|
|
356
399
|
name=name,
|
|
357
400
|
iso_utc_time=iso_utc_time,
|
|
@@ -362,7 +405,7 @@ class AstrologicalSubject:
|
|
|
362
405
|
lng=float(lng),
|
|
363
406
|
lat=float(lat),
|
|
364
407
|
geonames_username=resolved_geonames,
|
|
365
|
-
zodiac_type=(
|
|
408
|
+
zodiac_type=(normalized_zodiac_type or DEFAULT_ZODIAC_TYPE), # type: ignore[arg-type]
|
|
366
409
|
sidereal_mode=sidereal_mode,
|
|
367
410
|
houses_system_identifier=(houses_system_identifier or DEFAULT_HOUSES_SYSTEM_IDENTIFIER), # type: ignore[arg-type]
|
|
368
411
|
perspective_type=(perspective_type or DEFAULT_PERSPECTIVE_TYPE), # type: ignore[arg-type]
|
kerykeion/charts/chart_drawer.py
CHANGED
|
@@ -78,6 +78,9 @@ from kerykeion.settings.chart_defaults import (
|
|
|
78
78
|
from typing import List, Literal
|
|
79
79
|
|
|
80
80
|
|
|
81
|
+
logger = logging.getLogger(__name__)
|
|
82
|
+
|
|
83
|
+
|
|
81
84
|
class ChartDrawer:
|
|
82
85
|
"""
|
|
83
86
|
ChartDrawer generates astrological chart visualizations as SVG files from pre-computed chart data.
|
|
@@ -315,7 +318,7 @@ class ChartDrawer:
|
|
|
315
318
|
|
|
316
319
|
active_points_count = len(self.available_planets_setting)
|
|
317
320
|
if active_points_count > 24:
|
|
318
|
-
|
|
321
|
+
logger.warning(
|
|
319
322
|
"ChartDrawer detected %s active celestial points; rendering may look crowded beyond 24.",
|
|
320
323
|
active_points_count,
|
|
321
324
|
)
|
|
@@ -856,7 +859,7 @@ class ChartDrawer:
|
|
|
856
859
|
try:
|
|
857
860
|
required_width = self._estimate_required_width_full()
|
|
858
861
|
except Exception as e:
|
|
859
|
-
|
|
862
|
+
logger.debug("Auto-size width calculation failed: %s", e)
|
|
860
863
|
return
|
|
861
864
|
|
|
862
865
|
minimum_width = self._minimum_width_for_chart_type()
|
|
@@ -1271,7 +1274,7 @@ class ChartDrawer:
|
|
|
1271
1274
|
template_dict["top_left_5"] = f"{self._translate('day_of_week', 'Day of Week')}: {localized_weekday}" # type: ignore
|
|
1272
1275
|
|
|
1273
1276
|
# Bottom left section
|
|
1274
|
-
if self.first_obj.zodiac_type == "
|
|
1277
|
+
if self.first_obj.zodiac_type == "Tropical":
|
|
1275
1278
|
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1276
1279
|
else:
|
|
1277
1280
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
@@ -1433,7 +1436,7 @@ class ChartDrawer:
|
|
|
1433
1436
|
template_dict["top_left_5"] = f"{latitude_string} / {longitude_string}"
|
|
1434
1437
|
|
|
1435
1438
|
# Bottom left section
|
|
1436
|
-
if self.first_obj.zodiac_type == "
|
|
1439
|
+
if self.first_obj.zodiac_type == "Tropical":
|
|
1437
1440
|
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1438
1441
|
else:
|
|
1439
1442
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
@@ -1589,7 +1592,7 @@ class ChartDrawer:
|
|
|
1589
1592
|
template_dict["top_left_5"] = ""#f"{self._translate('type', 'Type')}: {self._translate(self.chart_type, self.chart_type)}"
|
|
1590
1593
|
|
|
1591
1594
|
# Bottom left section
|
|
1592
|
-
if self.first_obj.zodiac_type == "
|
|
1595
|
+
if self.first_obj.zodiac_type == "Tropical":
|
|
1593
1596
|
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1594
1597
|
else:
|
|
1595
1598
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
@@ -1609,9 +1612,9 @@ class ChartDrawer:
|
|
|
1609
1612
|
|
|
1610
1613
|
template_dict["bottom_left_4"] = f'{self._translate("perspective_type", "Perspective")}: {self._translate(self.second_obj.perspective_type.lower().replace(" ", "_"), self.second_obj.perspective_type)}' # type: ignore
|
|
1611
1614
|
|
|
1612
|
-
# Moon phase section calculations - use
|
|
1613
|
-
if self.
|
|
1614
|
-
template_dict["makeLunarPhase"] = makeLunarPhase(self.
|
|
1615
|
+
# Moon phase section calculations - use transit subject data only
|
|
1616
|
+
if self.second_obj is not None and getattr(self.second_obj, "lunar_phase", None):
|
|
1617
|
+
template_dict["makeLunarPhase"] = makeLunarPhase(self.second_obj.lunar_phase["degrees_between_s_m"], self.geolat)
|
|
1615
1618
|
else:
|
|
1616
1619
|
template_dict["makeLunarPhase"] = ""
|
|
1617
1620
|
|
|
@@ -1767,7 +1770,7 @@ class ChartDrawer:
|
|
|
1767
1770
|
template_dict["top_left_5"] = format_datetime_with_timezone(self.second_obj.iso_formatted_local_datetime) # type: ignore
|
|
1768
1771
|
|
|
1769
1772
|
# Bottom left section
|
|
1770
|
-
if self.first_obj.zodiac_type == "
|
|
1773
|
+
if self.first_obj.zodiac_type == "Tropical":
|
|
1771
1774
|
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1772
1775
|
else:
|
|
1773
1776
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
@@ -1967,7 +1970,7 @@ class ChartDrawer:
|
|
|
1967
1970
|
template_dict["top_left_5"] = f"{latitude_string} / {longitude_string}"
|
|
1968
1971
|
|
|
1969
1972
|
# Bottom left section
|
|
1970
|
-
if self.first_obj.zodiac_type == "
|
|
1973
|
+
if self.first_obj.zodiac_type == "Tropical":
|
|
1971
1974
|
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
1972
1975
|
else:
|
|
1973
1976
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
@@ -2140,7 +2143,7 @@ class ChartDrawer:
|
|
|
2140
2143
|
template_dict["top_left_5"] = f"{self._translate('type', 'Type')}: {self._translate('lunar_return', 'Lunar Return')}"
|
|
2141
2144
|
|
|
2142
2145
|
# Bottom left section
|
|
2143
|
-
if self.first_obj.zodiac_type == "
|
|
2146
|
+
if self.first_obj.zodiac_type == "Tropical":
|
|
2144
2147
|
zodiac_info = f"{self._translate('zodiac', 'Zodiac')}: {self._translate('tropical', 'Tropical')}"
|
|
2145
2148
|
else:
|
|
2146
2149
|
mode_const = "SIDM_" + self.first_obj.sidereal_mode # type: ignore
|
|
@@ -2237,7 +2240,7 @@ class ChartDrawer:
|
|
|
2237
2240
|
|
|
2238
2241
|
# return filename
|
|
2239
2242
|
|
|
2240
|
-
|
|
2243
|
+
logger.debug("Template dictionary includes %s fields", len(td.model_dump()))
|
|
2241
2244
|
|
|
2242
2245
|
self._create_template_dictionary()
|
|
2243
2246
|
|
|
@@ -48,10 +48,19 @@ License: AGPL-3.0
|
|
|
48
48
|
|
|
49
49
|
from kerykeion import AstrologicalSubjectFactory
|
|
50
50
|
from kerykeion.schemas.kr_models import AstrologicalSubjectModel
|
|
51
|
-
from kerykeion.utilities import
|
|
51
|
+
from kerykeion.utilities import (
|
|
52
|
+
get_houses_list,
|
|
53
|
+
get_available_astrological_points_list,
|
|
54
|
+
normalize_zodiac_type,
|
|
55
|
+
)
|
|
52
56
|
from kerykeion.astrological_subject_factory import DEFAULT_HOUSES_SYSTEM_IDENTIFIER, DEFAULT_PERSPECTIVE_TYPE, DEFAULT_ZODIAC_TYPE
|
|
53
|
-
from kerykeion.schemas import
|
|
54
|
-
|
|
57
|
+
from kerykeion.schemas import (
|
|
58
|
+
EphemerisDictModel,
|
|
59
|
+
SiderealMode,
|
|
60
|
+
HousesSystemIdentifier,
|
|
61
|
+
PerspectiveType,
|
|
62
|
+
ZodiacType,
|
|
63
|
+
)
|
|
55
64
|
from datetime import datetime, timedelta
|
|
56
65
|
from typing import Literal, Union, List
|
|
57
66
|
import logging
|
|
@@ -161,7 +170,7 @@ class EphemerisDataFactory:
|
|
|
161
170
|
self.lng = lng
|
|
162
171
|
self.tz_str = tz_str
|
|
163
172
|
self.is_dst = is_dst
|
|
164
|
-
self.zodiac_type = zodiac_type
|
|
173
|
+
self.zodiac_type = normalize_zodiac_type(zodiac_type)
|
|
165
174
|
self.sidereal_mode = sidereal_mode
|
|
166
175
|
self.houses_system_identifier = houses_system_identifier
|
|
167
176
|
self.perspective_type = perspective_type
|
kerykeion/fetch_geonames.py
CHANGED
|
@@ -6,13 +6,16 @@ License: AGPL-3.0
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
import
|
|
9
|
+
from logging import getLogger
|
|
10
10
|
from datetime import timedelta
|
|
11
11
|
from requests import Request
|
|
12
12
|
from requests_cache import CachedSession
|
|
13
13
|
from typing import Union
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
logger = getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
16
19
|
class FetchGeonames:
|
|
17
20
|
"""
|
|
18
21
|
Class to handle requests to the GeoNames API for location data and timezone information.
|
|
@@ -63,21 +66,21 @@ class FetchGeonames:
|
|
|
63
66
|
params = {"lat": lat, "lng": lon, "username": self.username}
|
|
64
67
|
|
|
65
68
|
prepared_request = Request("GET", self.timezone_url, params=params).prepare()
|
|
66
|
-
|
|
69
|
+
logger.debug("GeoNames timezone lookup url=%s", prepared_request.url)
|
|
67
70
|
|
|
68
71
|
try:
|
|
69
72
|
response = self.session.send(prepared_request)
|
|
70
73
|
response_json = response.json()
|
|
71
74
|
|
|
72
75
|
except Exception as e:
|
|
73
|
-
|
|
76
|
+
logger.error("GeoNames timezone request failed for %s: %s", self.timezone_url, e)
|
|
74
77
|
return {}
|
|
75
78
|
|
|
76
79
|
try:
|
|
77
80
|
timezone_data["timezonestr"] = response_json["timezoneId"]
|
|
78
81
|
|
|
79
82
|
except Exception as e:
|
|
80
|
-
|
|
83
|
+
logger.error("GeoNames timezone payload missing expected keys: %s", e)
|
|
81
84
|
return {}
|
|
82
85
|
|
|
83
86
|
if hasattr(response, "from_cache"):
|
|
@@ -109,15 +112,16 @@ class FetchGeonames:
|
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
prepared_request = Request("GET", self.base_url, params=params).prepare()
|
|
112
|
-
|
|
115
|
+
logger.debug("GeoNames search url=%s", prepared_request.url)
|
|
113
116
|
|
|
114
117
|
try:
|
|
115
118
|
response = self.session.send(prepared_request)
|
|
119
|
+
response.raise_for_status()
|
|
116
120
|
response_json = response.json()
|
|
117
|
-
|
|
121
|
+
logger.debug("GeoNames search response: %s", response_json)
|
|
118
122
|
|
|
119
123
|
except Exception as e:
|
|
120
|
-
|
|
124
|
+
logger.error("GeoNames search request failed for %s: %s", self.base_url, e)
|
|
121
125
|
return {}
|
|
122
126
|
|
|
123
127
|
try:
|
|
@@ -127,7 +131,7 @@ class FetchGeonames:
|
|
|
127
131
|
city_data_whitout_tz["countryCode"] = response_json["geonames"][0]["countryCode"]
|
|
128
132
|
|
|
129
133
|
except Exception as e:
|
|
130
|
-
|
|
134
|
+
logger.error("GeoNames search payload missing expected keys: %s", e)
|
|
131
135
|
return {}
|
|
132
136
|
|
|
133
137
|
if hasattr(response, "from_cache"):
|
|
@@ -147,15 +151,16 @@ class FetchGeonames:
|
|
|
147
151
|
timezone_response = self.__get_timezone(city_data_response["lat"], city_data_response["lng"])
|
|
148
152
|
|
|
149
153
|
except Exception as e:
|
|
150
|
-
|
|
154
|
+
logger.error("Unable to fetch timezone details: %s", e)
|
|
151
155
|
return {}
|
|
152
156
|
|
|
153
157
|
return {**timezone_response, **city_data_response}
|
|
154
158
|
|
|
155
159
|
|
|
156
160
|
if __name__ == "__main__":
|
|
157
|
-
|
|
158
|
-
setup_logging
|
|
161
|
+
"""Run a tiny demonstration when executing the module directly."""
|
|
162
|
+
from kerykeion.utilities import setup_logging as configure_logging
|
|
159
163
|
|
|
164
|
+
configure_logging("debug")
|
|
160
165
|
geonames = FetchGeonames("Montichiari", "IT")
|
|
161
166
|
print(geonames.get_serialized_data())
|
kerykeion/report.py
CHANGED
|
@@ -727,8 +727,7 @@ if __name__ == "__main__":
|
|
|
727
727
|
natal_subject.iso_formatted_local_datetime,
|
|
728
728
|
"Solar",
|
|
729
729
|
)
|
|
730
|
-
|
|
731
|
-
# Composite chart subject
|
|
730
|
+
# Derive a composite subject representing the pair's midpoint configuration
|
|
732
731
|
composite_subject = CompositeSubjectFactory(
|
|
733
732
|
natal_subject,
|
|
734
733
|
partner_subject,
|
kerykeion/schemas/kr_literals.py
CHANGED
|
@@ -47,5 +47,5 @@ def _deep_merge(base: Mapping[str, Any], overrides: Mapping[str, Any]) -> dict[s
|
|
|
47
47
|
merged[key] = deepcopy(value)
|
|
48
48
|
return merged
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
# Keep the public surface area explicit for downstream imports.
|
|
51
51
|
__all__ = ["SettingsSource", "load_settings_mapping", "LANGUAGE_SETTINGS"]
|
kerykeion/utilities.py
CHANGED
|
@@ -12,15 +12,108 @@ from kerykeion.schemas import (
|
|
|
12
12
|
LunarPhaseModel,
|
|
13
13
|
CompositeSubjectModel,
|
|
14
14
|
PlanetReturnModel,
|
|
15
|
+
ZodiacType,
|
|
15
16
|
)
|
|
16
|
-
from kerykeion.schemas.kr_literals import
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
from kerykeion.schemas.kr_literals import (
|
|
18
|
+
LunarPhaseEmoji,
|
|
19
|
+
LunarPhaseName,
|
|
20
|
+
PointType,
|
|
21
|
+
AstrologicalPoint,
|
|
22
|
+
Houses,
|
|
23
|
+
)
|
|
24
|
+
from typing import Union, Optional, get_args, cast
|
|
25
|
+
from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL, basicConfig, getLogger
|
|
19
26
|
import math
|
|
20
27
|
import re
|
|
21
28
|
from datetime import datetime
|
|
22
29
|
|
|
23
30
|
|
|
31
|
+
logger = getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
def normalize_zodiac_type(value: str) -> ZodiacType:
|
|
34
|
+
"""
|
|
35
|
+
Normalize a zodiac type string to its canonical representation.
|
|
36
|
+
|
|
37
|
+
Handles case-insensitive matching and legacy formats like "tropic" or "Tropic",
|
|
38
|
+
automatically converting them to the canonical forms "Tropical" or "Sidereal".
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
value: Input zodiac type string (case-insensitive).
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
ZodiacType: Canonical zodiac type ("Tropical" or "Sidereal").
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
ValueError: If `value` is not a recognized zodiac type.
|
|
48
|
+
|
|
49
|
+
Examples:
|
|
50
|
+
>>> normalize_zodiac_type("tropical")
|
|
51
|
+
'Tropical'
|
|
52
|
+
>>> normalize_zodiac_type("Tropic")
|
|
53
|
+
'Tropical'
|
|
54
|
+
>>> normalize_zodiac_type("SIDEREAL")
|
|
55
|
+
'Sidereal'
|
|
56
|
+
"""
|
|
57
|
+
# Normalize to lowercase for comparison
|
|
58
|
+
value_lower = value.lower()
|
|
59
|
+
|
|
60
|
+
# Map legacy and case-insensitive variants to canonical forms
|
|
61
|
+
if value_lower in ("tropical", "tropic"):
|
|
62
|
+
return cast(ZodiacType, "Tropical")
|
|
63
|
+
elif value_lower == "sidereal":
|
|
64
|
+
return cast(ZodiacType, "Sidereal")
|
|
65
|
+
else:
|
|
66
|
+
raise ValueError(
|
|
67
|
+
"'{value}' is not a valid zodiac type. Accepted values are: Tropical, Sidereal "
|
|
68
|
+
"(case-insensitive, 'tropic' also accepted as legacy).".format(value=value)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
_POINT_NUMBER_MAP: dict[str, int] = {
|
|
72
|
+
"Sun": 0,
|
|
73
|
+
"Moon": 1,
|
|
74
|
+
"Mercury": 2,
|
|
75
|
+
"Venus": 3,
|
|
76
|
+
"Mars": 4,
|
|
77
|
+
"Jupiter": 5,
|
|
78
|
+
"Saturn": 6,
|
|
79
|
+
"Uranus": 7,
|
|
80
|
+
"Neptune": 8,
|
|
81
|
+
"Pluto": 9,
|
|
82
|
+
"Mean_North_Lunar_Node": 10,
|
|
83
|
+
"True_North_Lunar_Node": 11,
|
|
84
|
+
# Swiss Ephemeris has no dedicated IDs for the south nodes; we reserve high values.
|
|
85
|
+
"Mean_South_Lunar_Node": 1000,
|
|
86
|
+
"True_South_Lunar_Node": 1100,
|
|
87
|
+
"Chiron": 15,
|
|
88
|
+
"Mean_Lilith": 12,
|
|
89
|
+
"Ascendant": 9900,
|
|
90
|
+
"Descendant": 9901,
|
|
91
|
+
"Medium_Coeli": 9902,
|
|
92
|
+
"Imum_Coeli": 9903,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# Logging helpers
|
|
96
|
+
def setup_logging(level: str) -> None:
|
|
97
|
+
"""Configure the root logger so demo scripts share the same formatting."""
|
|
98
|
+
normalized_level = (level or "").strip().lower()
|
|
99
|
+
level_map: dict[str, int] = {
|
|
100
|
+
"debug": DEBUG,
|
|
101
|
+
"info": INFO,
|
|
102
|
+
"warning": WARNING,
|
|
103
|
+
"error": ERROR,
|
|
104
|
+
"critical": CRITICAL,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
selected_level = level_map.get(normalized_level, INFO)
|
|
108
|
+
basicConfig(
|
|
109
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
110
|
+
level=selected_level,
|
|
111
|
+
)
|
|
112
|
+
logger.setLevel(selected_level)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
24
117
|
def get_number_from_name(name: AstrologicalPoint) -> int:
|
|
25
118
|
"""
|
|
26
119
|
Convert an astrological point name to its corresponding numerical identifier.
|
|
@@ -35,49 +128,10 @@ def get_number_from_name(name: AstrologicalPoint) -> int:
|
|
|
35
128
|
KerykeionException: If the name is not recognized
|
|
36
129
|
"""
|
|
37
130
|
|
|
38
|
-
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
elif name == "Mercury":
|
|
43
|
-
return 2
|
|
44
|
-
elif name == "Venus":
|
|
45
|
-
return 3
|
|
46
|
-
elif name == "Mars":
|
|
47
|
-
return 4
|
|
48
|
-
elif name == "Jupiter":
|
|
49
|
-
return 5
|
|
50
|
-
elif name == "Saturn":
|
|
51
|
-
return 6
|
|
52
|
-
elif name == "Uranus":
|
|
53
|
-
return 7
|
|
54
|
-
elif name == "Neptune":
|
|
55
|
-
return 8
|
|
56
|
-
elif name == "Pluto":
|
|
57
|
-
return 9
|
|
58
|
-
elif name == "Mean_North_Lunar_Node":
|
|
59
|
-
return 10
|
|
60
|
-
elif name == "True_North_Lunar_Node":
|
|
61
|
-
return 11
|
|
62
|
-
# Note: Swiss ephemeris library has no constants for south nodes. We're using integers >= 1000 for them.
|
|
63
|
-
elif name == "Mean_South_Lunar_Node":
|
|
64
|
-
return 1000
|
|
65
|
-
elif name == "True_South_Lunar_Node":
|
|
66
|
-
return 1100
|
|
67
|
-
elif name == "Chiron":
|
|
68
|
-
return 15
|
|
69
|
-
elif name == "Mean_Lilith":
|
|
70
|
-
return 12
|
|
71
|
-
elif name == "Ascendant": # TODO: Is this needed?
|
|
72
|
-
return 9900
|
|
73
|
-
elif name == "Descendant": # TODO: Is this needed?
|
|
74
|
-
return 9901
|
|
75
|
-
elif name == "Medium_Coeli": # TODO: Is this needed?
|
|
76
|
-
return 9902
|
|
77
|
-
elif name == "Imum_Coeli": # TODO: Is this needed?
|
|
78
|
-
return 9903
|
|
79
|
-
else:
|
|
80
|
-
raise KerykeionException(f"Error in getting number from name! Name: {name}")
|
|
131
|
+
try:
|
|
132
|
+
return _POINT_NUMBER_MAP[str(name)]
|
|
133
|
+
except KeyError as exc: # pragma: no cover - defensive branch
|
|
134
|
+
raise KerykeionException(f"Error in getting number from name! Name: {name}") from exc
|
|
81
135
|
|
|
82
136
|
|
|
83
137
|
def get_kerykeion_point_from_degree(
|
|
@@ -124,7 +178,6 @@ def get_kerykeion_point_from_degree(
|
|
|
124
178
|
sign_index = int(degree // 30)
|
|
125
179
|
sign_degree = degree % 30
|
|
126
180
|
zodiac_sign = ZODIAC_SIGNS[sign_index]
|
|
127
|
-
|
|
128
181
|
return KerykeionPointModel(
|
|
129
182
|
name=name,
|
|
130
183
|
quality=zodiac_sign.quality,
|
|
@@ -139,87 +192,34 @@ def get_kerykeion_point_from_degree(
|
|
|
139
192
|
declination=declination,
|
|
140
193
|
)
|
|
141
194
|
|
|
195
|
+
# Angular helpers
|
|
196
|
+
def is_point_between(start_angle: Union[int, float], end_angle: Union[int, float], candidate: Union[int, float]) -> bool:
|
|
197
|
+
"""Return True when ``candidate`` lies on the clockwise arc from ``start_angle`` to ``end_angle``."""
|
|
142
198
|
|
|
143
|
-
|
|
144
|
-
"""
|
|
145
|
-
Configure logging for the application.
|
|
146
|
-
|
|
147
|
-
Args:
|
|
148
|
-
level: Log level as string (debug, info, warning, error, critical)
|
|
149
|
-
"""
|
|
150
|
-
logging_options: dict[str, int] = {
|
|
151
|
-
"debug": logging.DEBUG,
|
|
152
|
-
"info": logging.INFO,
|
|
153
|
-
"warning": logging.WARNING,
|
|
154
|
-
"error": logging.ERROR,
|
|
155
|
-
"critical": logging.CRITICAL,
|
|
156
|
-
}
|
|
157
|
-
format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
158
|
-
loglevel: int = logging_options.get(level, logging.INFO)
|
|
159
|
-
logging.basicConfig(format=format, level=loglevel)
|
|
160
|
-
|
|
199
|
+
normalize = lambda value: value % 360
|
|
161
200
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
Special rules:
|
|
169
|
-
- If evaluated_point equals start_point, returns True
|
|
170
|
-
- If evaluated_point equals end_point, returns False
|
|
171
|
-
- The arc between start_point and end_point must not exceed 180°
|
|
172
|
-
|
|
173
|
-
Args:
|
|
174
|
-
start_point: The starting point on the circle
|
|
175
|
-
end_point: The ending point on the circle
|
|
176
|
-
evaluated_point: The point to evaluate
|
|
177
|
-
|
|
178
|
-
Returns:
|
|
179
|
-
True if evaluated_point is between start_point and end_point, False otherwise
|
|
180
|
-
|
|
181
|
-
Raises:
|
|
182
|
-
KerykeionException: If the angular difference exceeds 180°
|
|
183
|
-
"""
|
|
184
|
-
|
|
185
|
-
# Normalize angles to [0, 360)
|
|
186
|
-
start_point = start_point % 360
|
|
187
|
-
end_point = end_point % 360
|
|
188
|
-
evaluated_point = evaluated_point % 360
|
|
189
|
-
|
|
190
|
-
# Compute angular difference
|
|
191
|
-
angular_difference = math.fmod(end_point - start_point + 360, 360)
|
|
192
|
-
|
|
193
|
-
# Ensure the range is not greater than 180°. Otherwise, it is not truly defined what
|
|
194
|
-
# being located in between two points on a circle actually means.
|
|
195
|
-
if angular_difference > 180:
|
|
201
|
+
start = normalize(start_angle)
|
|
202
|
+
end = normalize(end_angle)
|
|
203
|
+
target = normalize(candidate)
|
|
204
|
+
span = (end - start) % 360
|
|
205
|
+
if span > 180:
|
|
196
206
|
raise KerykeionException(
|
|
197
|
-
f"The angle between start and end point is not allowed to exceed 180°, yet is: {
|
|
207
|
+
f"The angle between start and end point is not allowed to exceed 180°, yet is: {span}"
|
|
198
208
|
)
|
|
199
|
-
|
|
200
|
-
# Handle explicitly when evaluated_point == start_point. Note: It may happen for mathematical
|
|
201
|
-
# reasons that evaluated_point and start_point deviate very slightly from each other, but
|
|
202
|
-
# should really be same value. This case is captured later below by the term 0 <= p1_p3.
|
|
203
|
-
if evaluated_point == start_point:
|
|
209
|
+
if target == start:
|
|
204
210
|
return True
|
|
205
|
-
|
|
206
|
-
# Handle explicitly when evaluated_point == end_point
|
|
207
|
-
if evaluated_point == end_point:
|
|
211
|
+
if target == end:
|
|
208
212
|
return False
|
|
213
|
+
distance_from_start = (target - start) % 360
|
|
214
|
+
return distance_from_start < span
|
|
209
215
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
# Check if point lies in the interval
|
|
214
|
-
return (0 <= p1_p3) and (p1_p3 < angular_difference)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def get_planet_house(planet_position_degree: Union[int, float], houses_degree_ut_list: list) -> Houses:
|
|
216
|
+
# House helpers
|
|
217
|
+
def get_planet_house(planet_degree: Union[int, float], houses_degree_ut_list: list) -> Houses:
|
|
218
218
|
"""
|
|
219
219
|
Determine which house contains a planet based on its degree position.
|
|
220
220
|
|
|
221
221
|
Args:
|
|
222
|
-
|
|
222
|
+
planet_degree: The planet's position in degrees (0-360)
|
|
223
223
|
houses_degree_ut_list: List of house cusp degrees
|
|
224
224
|
|
|
225
225
|
Returns:
|
|
@@ -236,11 +236,11 @@ def get_planet_house(planet_position_degree: Union[int, float], houses_degree_ut
|
|
|
236
236
|
start_degree = houses_degree_ut_list[i]
|
|
237
237
|
end_degree = houses_degree_ut_list[(i + 1) % len(houses_degree_ut_list)]
|
|
238
238
|
|
|
239
|
-
if is_point_between(start_degree, end_degree,
|
|
239
|
+
if is_point_between(start_degree, end_degree, planet_degree):
|
|
240
240
|
return house_names[i]
|
|
241
241
|
|
|
242
242
|
# If no house is found, raise an error
|
|
243
|
-
raise ValueError(f"Error in house calculation, planet: {
|
|
243
|
+
raise ValueError(f"Error in house calculation, planet: {planet_degree}, houses: {houses_degree_ut_list}")
|
|
244
244
|
|
|
245
245
|
|
|
246
246
|
def get_moon_emoji_from_phase_int(phase: int) -> LunarPhaseEmoji:
|
|
@@ -334,11 +334,11 @@ def check_and_adjust_polar_latitude(latitude: float) -> float:
|
|
|
334
334
|
"""
|
|
335
335
|
if latitude > 66.0:
|
|
336
336
|
latitude = 66.0
|
|
337
|
-
|
|
337
|
+
logger.info("Latitude capped at 66° to keep house calculations stable.")
|
|
338
338
|
|
|
339
339
|
elif latitude < -66.0:
|
|
340
340
|
latitude = -66.0
|
|
341
|
-
|
|
341
|
+
logger.info("Latitude capped at -66° to keep house calculations stable.")
|
|
342
342
|
|
|
343
343
|
return latitude
|
|
344
344
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kerykeion
|
|
3
|
-
Version: 5.1.
|
|
3
|
+
Version: 5.1.7
|
|
4
4
|
Summary: A Python library for astrological calculations, including natal charts, houses, planetary aspects, and SVG chart generation.
|
|
5
5
|
Project-URL: Homepage, https://www.kerykeion.net/
|
|
6
6
|
Project-URL: Repository, https://github.com/g-battaglia/kerykeion
|
|
@@ -1781,6 +1781,8 @@ Since the AstrologerAPI is an external third-party service, using it does _not_
|
|
|
1781
1781
|
|
|
1782
1782
|
Contributions are welcome! Feel free to submit pull requests or report issues.
|
|
1783
1783
|
|
|
1784
|
+
By submitting a contribution, you agree to assign the copyright of that contribution to the maintainer. The project stays openly available under the AGPL for everyone, while the re-licensing option helps sustain future development. Your authorship remains acknowledged in the commit history and release notes.
|
|
1785
|
+
|
|
1784
1786
|
## Citations
|
|
1785
1787
|
|
|
1786
1788
|
If using Kerykeion in published or academic work, please cite as follows:
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
kerykeion/__init__.py,sha256=7gI_kWXhsmEK4SvNV6CkRmI0yjA3r7EO8UfQc_44UZU,1963
|
|
2
|
-
kerykeion/astrological_subject_factory.py,sha256=
|
|
3
|
-
kerykeion/backword.py,sha256=
|
|
2
|
+
kerykeion/astrological_subject_factory.py,sha256=qR6dWULcF4J2ym2oTI4CQ-zfQfMgAFNyLwhGXhJkg-A,94740
|
|
3
|
+
kerykeion/backword.py,sha256=aZrC6gRhLuewv3PvpHWlPvqrDGxspCEN2mMAh8tLtfM,34500
|
|
4
4
|
kerykeion/chart_data_factory.py,sha256=gtAlZs_IjPMUJUitLjkRFCESmAj-wEOlYdCPQ2b8XwA,25123
|
|
5
5
|
kerykeion/composite_subject_factory.py,sha256=eUtjThDlYr6SQsEi02_CgO1kEMUMYgQGzR5rX91GEwY,17120
|
|
6
|
-
kerykeion/ephemeris_data_factory.py,sha256=
|
|
7
|
-
kerykeion/fetch_geonames.py,sha256=
|
|
6
|
+
kerykeion/ephemeris_data_factory.py,sha256=UKgoJQSqiyy4U0jNw23NI_BP0kbZblJU5mtBnNZtnb0,20417
|
|
7
|
+
kerykeion/fetch_geonames.py,sha256=VO-TK4m_xSE62yWE5cf6CE2OLVfkPLeTPqXw8igzDnU,5619
|
|
8
8
|
kerykeion/planetary_return_factory.py,sha256=bIVPqa2gs7hYHi8aaMfVr4U99xWZk3LmYqZI9KG6ACo,37572
|
|
9
9
|
kerykeion/relationship_score_factory.py,sha256=pVrsRlFs__bfVe8K3cOirsnRtdBOW2DbnKqPa7jCWF0,11396
|
|
10
|
-
kerykeion/report.py,sha256=
|
|
10
|
+
kerykeion/report.py,sha256=fHGzPh9vhDIWzT_Gr4V5KrfLjiDWLlSlBgOk6-DeH80,31463
|
|
11
11
|
kerykeion/transits_time_range_factory.py,sha256=YRSFVa2MIZFQMPbEL2njKd-P7p431zoAsINrddZz5Yw,13934
|
|
12
|
-
kerykeion/utilities.py,sha256=
|
|
12
|
+
kerykeion/utilities.py,sha256=AqcJ9zmVEcwiurMfN63MDSeegJ1dJ4L1sQVJeoNIGOE,24016
|
|
13
13
|
kerykeion/aspects/__init__.py,sha256=csJmxvLdBu-bHuW676f3dpY__Qyc6LwRyrpWVTh3n1A,287
|
|
14
14
|
kerykeion/aspects/aspects_factory.py,sha256=XCuOOpo0ZW7sihYT2f50bLVpebEk19b9EtEjXonwte0,24156
|
|
15
15
|
kerykeion/aspects/aspects_utils.py,sha256=00-MMLEGChpceab8sHKB1_qg6EG4ycTG2u2vYZcyLmQ,5784
|
|
16
16
|
kerykeion/charts/__init__.py,sha256=i9NMZ7LdkllPlqQSi1or9gTobHbROGDKmJhBDO4R0mA,128
|
|
17
|
-
kerykeion/charts/chart_drawer.py,sha256=
|
|
17
|
+
kerykeion/charts/chart_drawer.py,sha256=Rhv2eVV2G_GBb6Khh4uor9sqSH6KJ5i6RA5ZFpVPzuI,122333
|
|
18
18
|
kerykeion/charts/charts_utils.py,sha256=iwgDhVc_GwKuQBZ6JNmn6RWVILD5KIcjbrnDTR3wrAc,70911
|
|
19
19
|
kerykeion/charts/draw_planets.py,sha256=tIj3FeLLomVSbCaZUxfw_qBEB3pxi4EIEhqaeTgTyTY,29061
|
|
20
20
|
kerykeion/charts/templates/aspect_grid_only.xml,sha256=v3QtNMjk-kBdUTfB0r6thg--Ta_tNFdRQCzdk5PAycY,86429
|
|
@@ -38,13 +38,13 @@ kerykeion/kr_types/settings_models.py,sha256=xtpsrhjmhdowDSBeQ7TEMR53-uEEspCoXKC
|
|
|
38
38
|
kerykeion/schemas/__init__.py,sha256=EcwbnoYPKLq3m7n5s2cEZ8UyWpxdmHXbvM23hLNBNBI,2376
|
|
39
39
|
kerykeion/schemas/chart_template_model.py,sha256=fQ_EZ8ccOgNd4gXu5KilF1dUH9B2RVCDLHc09YkYLyY,8978
|
|
40
40
|
kerykeion/schemas/kerykeion_exception.py,sha256=vTYdwj_mL-Q-MqHJvEzzBXxQ5YI2kAwUC6ImoWxMKXc,454
|
|
41
|
-
kerykeion/schemas/kr_literals.py,sha256=
|
|
41
|
+
kerykeion/schemas/kr_literals.py,sha256=mvPH3_TyuF5GTYKfIGk9SpxbuW7uYhSlp20SZJ7l6BY,5658
|
|
42
42
|
kerykeion/schemas/kr_models.py,sha256=e1PQxUqC437IWIVKrOi71NVR5bEV7KGhF_JAaxs9zN0,21945
|
|
43
43
|
kerykeion/schemas/settings_models.py,sha256=NlOW9T7T5kD5Dzna1UOdb7XPQeQnzMOu0y4-ApERxPw,17619
|
|
44
44
|
kerykeion/settings/__init__.py,sha256=IJUqkYTpvmbKecVeCbsiL1qU_4xWc78u4OrvN_T3ZAI,624
|
|
45
45
|
kerykeion/settings/chart_defaults.py,sha256=TSm2hXCxym3I7XpIqIMBLWM253Z0dCGbhPi2MpWbD_0,12490
|
|
46
46
|
kerykeion/settings/config_constants.py,sha256=D1PApNT7Zldlv8QINmaKnyLovY5UJ2FsAqHNTTPd5ps,3717
|
|
47
|
-
kerykeion/settings/kerykeion_settings.py,sha256=
|
|
47
|
+
kerykeion/settings/kerykeion_settings.py,sha256=aeRlxvy2GwC-mxoD_DFMXMoO4yPQp1XQbEAGVQat0Wo,1947
|
|
48
48
|
kerykeion/settings/translation_strings.py,sha256=UYxiZT5aiNZ4tpQuTauIlXwMm3tzfz6QE9DPNVtlHdo,56412
|
|
49
49
|
kerykeion/settings/translations.py,sha256=A_Zwr-ujvxBLvE4a87-28pM3KifdUaAvsR3XvMZNg0s,2377
|
|
50
50
|
kerykeion/sweph/README.md,sha256=L7FtNAJTWtrZNGKa8MX87SjduFYPYxwWhaI5fmtzNZo,73
|
|
@@ -57,7 +57,7 @@ kerykeion/sweph/ast28/se28978s.se1,sha256=nU2Qp-ELc_tzFnRc1QT6uVueWXEipvhYDgfQRX
|
|
|
57
57
|
kerykeion/sweph/ast50/se50000s.se1,sha256=9jTrPlIrZMOBWC9cNgwzcfz0KBHdXFZoY9-NZ_HtECo,15748
|
|
58
58
|
kerykeion/sweph/ast90/se90377s.se1,sha256=bto2x4LtBv8b1ej1XhVFYq-kfHO9cczbKV9U1f9UVu4,10288
|
|
59
59
|
kerykeion/sweph/ast90/se90482s.se1,sha256=uHxz6bP4K8zgtQFrlWFwxrYfmqm5kXxsg6OYhAIUbAA,16173
|
|
60
|
-
kerykeion-5.1.
|
|
61
|
-
kerykeion-5.1.
|
|
62
|
-
kerykeion-5.1.
|
|
63
|
-
kerykeion-5.1.
|
|
60
|
+
kerykeion-5.1.7.dist-info/METADATA,sha256=w1pDxVeTBbyLbZ-m6qCBi9-gSx8eI1fXUUHm1_g1Gf0,61756
|
|
61
|
+
kerykeion-5.1.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
62
|
+
kerykeion-5.1.7.dist-info/licenses/LICENSE,sha256=UTLH8EdbAsgQei4PA2PnBCPGLSZkq5J-dhkyJuXgWQU,34273
|
|
63
|
+
kerykeion-5.1.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|