kerykeion 3.1.1__py3-none-any.whl → 5.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kerykeion might be problematic. Click here for more details.
- kerykeion/__init__.py +58 -141
- kerykeion/aspects/__init__.py +14 -0
- kerykeion/aspects/aspects_factory.py +568 -0
- kerykeion/aspects/aspects_utils.py +164 -0
- kerykeion/astrological_subject_factory.py +1901 -0
- kerykeion/backword.py +820 -0
- kerykeion/chart_data_factory.py +552 -0
- kerykeion/charts/__init__.py +5 -0
- kerykeion/charts/chart_drawer.py +2794 -0
- kerykeion/charts/charts_utils.py +1840 -0
- kerykeion/charts/draw_planets.py +658 -0
- kerykeion/charts/templates/aspect_grid_only.xml +596 -0
- kerykeion/charts/templates/chart.xml +741 -0
- kerykeion/charts/templates/wheel_only.xml +653 -0
- kerykeion/charts/themes/black-and-white.css +148 -0
- kerykeion/charts/themes/classic.css +113 -0
- kerykeion/charts/themes/dark-high-contrast.css +159 -0
- kerykeion/charts/themes/dark.css +160 -0
- kerykeion/charts/themes/light.css +160 -0
- kerykeion/charts/themes/strawberry.css +158 -0
- kerykeion/composite_subject_factory.py +408 -0
- kerykeion/ephemeris_data_factory.py +443 -0
- kerykeion/fetch_geonames.py +105 -61
- kerykeion/house_comparison/__init__.py +6 -0
- kerykeion/house_comparison/house_comparison_factory.py +103 -0
- kerykeion/house_comparison/house_comparison_utils.py +126 -0
- kerykeion/kr_types/__init__.py +70 -0
- kerykeion/kr_types/chart_template_model.py +20 -0
- kerykeion/kr_types/kerykeion_exception.py +20 -0
- kerykeion/kr_types/kr_literals.py +20 -0
- kerykeion/kr_types/kr_models.py +20 -0
- kerykeion/kr_types/settings_models.py +20 -0
- kerykeion/planetary_return_factory.py +805 -0
- kerykeion/relationship_score_factory.py +301 -0
- kerykeion/report.py +779 -0
- kerykeion/schemas/__init__.py +106 -0
- kerykeion/schemas/chart_template_model.py +367 -0
- kerykeion/schemas/kerykeion_exception.py +20 -0
- kerykeion/schemas/kr_literals.py +181 -0
- kerykeion/schemas/kr_models.py +603 -0
- kerykeion/schemas/settings_models.py +188 -0
- kerykeion/settings/__init__.py +20 -0
- kerykeion/settings/chart_defaults.py +444 -0
- kerykeion/settings/config_constants.py +152 -0
- kerykeion/settings/kerykeion_settings.py +51 -0
- kerykeion/settings/translation_strings.py +1499 -0
- kerykeion/settings/translations.py +74 -0
- kerykeion/sweph/README.md +3 -0
- kerykeion/sweph/ast136/s136108s.se1 +0 -0
- kerykeion/sweph/ast136/s136199s.se1 +0 -0
- kerykeion/sweph/ast136/s136472s.se1 +0 -0
- kerykeion/sweph/ast28/se28978s.se1 +0 -0
- kerykeion/sweph/ast50/se50000s.se1 +0 -0
- kerykeion/sweph/ast90/se90377s.se1 +0 -0
- kerykeion/sweph/ast90/se90482s.se1 +0 -0
- kerykeion/sweph/seas_18.se1 +0 -0
- kerykeion/sweph/sefstars.txt +1602 -0
- kerykeion/transits_time_range_factory.py +302 -0
- kerykeion/utilities.py +762 -130
- kerykeion-5.1.9.dist-info/METADATA +1793 -0
- kerykeion-5.1.9.dist-info/RECORD +63 -0
- {kerykeion-3.1.1.dist-info → kerykeion-5.1.9.dist-info}/WHEEL +1 -2
- kerykeion-5.1.9.dist-info/licenses/LICENSE +661 -0
- kerykeion/aspects.py +0 -331
- kerykeion/charts/charts_svg.py +0 -1607
- kerykeion/charts/templates/basic.xml +0 -285
- kerykeion/charts/templates/extended.xml +0 -294
- kerykeion/kr.config.json +0 -464
- kerykeion/main.py +0 -595
- kerykeion/print_all_data.py +0 -44
- kerykeion/relationship_score.py +0 -219
- kerykeion/types.py +0 -190
- kerykeion-3.1.1.dist-info/METADATA +0 -204
- kerykeion-3.1.1.dist-info/RECORD +0 -17
- kerykeion-3.1.1.dist-info/top_level.txt +0 -1
kerykeion/fetch_geonames.py
CHANGED
|
@@ -1,43 +1,60 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
1
2
|
"""
|
|
2
|
-
|
|
3
|
+
Author: Giacomo Battaglia
|
|
4
|
+
Copyright: (C) 2025 Kerykeion Project
|
|
5
|
+
License: AGPL-3.0
|
|
3
6
|
"""
|
|
4
|
-
#!/usr/bin/env python3
|
|
5
|
-
# -*- coding: utf-8 -*-
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
from logging import getLogger
|
|
10
|
+
from datetime import timedelta
|
|
11
|
+
from os import getenv
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Optional, Union
|
|
14
|
+
|
|
8
15
|
from requests import Request
|
|
9
16
|
from requests_cache import CachedSession
|
|
10
|
-
from typing import Union
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
|
|
19
|
+
logger = getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
DEFAULT_GEONAMES_CACHE_NAME = Path("cache") / "kerykeion_geonames_cache"
|
|
23
|
+
GEONAMES_CACHE_ENV_VAR = "KERYKEION_GEONAMES_CACHE_NAME"
|
|
16
24
|
|
|
17
25
|
|
|
18
26
|
class FetchGeonames:
|
|
19
27
|
"""
|
|
20
|
-
Class to handle requests to the
|
|
28
|
+
Class to handle requests to the GeoNames API for location data and timezone information.
|
|
29
|
+
|
|
30
|
+
This class provides cached access to the GeoNames API to retrieve location coordinates,
|
|
31
|
+
timezone information, and other geographical data for astrological calculations.
|
|
21
32
|
|
|
22
33
|
Args:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Optional
|
|
34
|
+
city_name: Name of the city to search for.
|
|
35
|
+
country_code: Two-letter country code (ISO 3166-1 alpha-2).
|
|
36
|
+
username: GeoNames username for API access, defaults to "century.boy".
|
|
37
|
+
cache_expire_after_days: Number of days to cache responses, defaults to 30.
|
|
38
|
+
cache_name: Optional path (directory or filename stem) used by requests-cache.
|
|
39
|
+
Defaults to "cache/kerykeion_geonames_cache" and may also be overridden
|
|
40
|
+
via the environment variable ``KERYKEION_GEONAMES_CACHE_NAME`` or by
|
|
41
|
+
calling :meth:`FetchGeonames.set_default_cache_name`.
|
|
28
42
|
"""
|
|
29
43
|
|
|
44
|
+
default_cache_name: Path = DEFAULT_GEONAMES_CACHE_NAME
|
|
45
|
+
|
|
30
46
|
def __init__(
|
|
31
|
-
self,
|
|
47
|
+
self,
|
|
48
|
+
city_name: str,
|
|
32
49
|
country_code: str,
|
|
33
50
|
username: str = "century.boy",
|
|
34
|
-
|
|
51
|
+
cache_expire_after_days=30,
|
|
52
|
+
cache_name: Optional[Union[str, Path]] = None,
|
|
35
53
|
):
|
|
36
|
-
|
|
37
54
|
self.session = CachedSession(
|
|
38
|
-
cache_name=
|
|
39
|
-
backend=
|
|
40
|
-
expire_after=
|
|
55
|
+
cache_name=str(self._resolve_cache_name(cache_name)),
|
|
56
|
+
backend="sqlite",
|
|
57
|
+
expire_after=timedelta(days=cache_expire_after_days),
|
|
41
58
|
)
|
|
42
59
|
|
|
43
60
|
self.username = username
|
|
@@ -45,111 +62,138 @@ class FetchGeonames:
|
|
|
45
62
|
self.country_code = country_code
|
|
46
63
|
self.base_url = "http://api.geonames.org/searchJSON"
|
|
47
64
|
self.timezone_url = "http://api.geonames.org/timezoneJSON"
|
|
48
|
-
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def set_default_cache_name(cls, cache_name: Union[str, Path]) -> None:
|
|
68
|
+
"""Override the default cache name used when none is provided."""
|
|
69
|
+
|
|
70
|
+
cls.default_cache_name = Path(cache_name)
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def _resolve_cache_name(cls, cache_name: Optional[Union[str, Path]]) -> Path:
|
|
74
|
+
"""Return the resolved cache name applying overrides in priority order."""
|
|
75
|
+
|
|
76
|
+
if cache_name is not None:
|
|
77
|
+
return Path(cache_name)
|
|
78
|
+
|
|
79
|
+
env_override = getenv(GEONAMES_CACHE_ENV_VAR)
|
|
80
|
+
if env_override:
|
|
81
|
+
return Path(env_override)
|
|
82
|
+
|
|
83
|
+
return cls.default_cache_name
|
|
49
84
|
|
|
50
85
|
def __get_timezone(self, lat: Union[str, float, int], lon: Union[str, float, int]) -> dict[str, str]:
|
|
51
86
|
"""
|
|
52
|
-
Get
|
|
87
|
+
Get timezone information for a given latitude and longitude.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
lat: Latitude coordinate.
|
|
91
|
+
lon: Longitude coordinate.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
dict: Timezone data including timezone string and cache status.
|
|
53
95
|
"""
|
|
54
96
|
# Dictionary that will be returned:
|
|
55
97
|
timezone_data = {}
|
|
56
98
|
|
|
57
|
-
params = {
|
|
58
|
-
"lat": lat,
|
|
59
|
-
"lng": lon,
|
|
60
|
-
"username": self.username
|
|
61
|
-
}
|
|
99
|
+
params = {"lat": lat, "lng": lon, "username": self.username}
|
|
62
100
|
|
|
63
|
-
prepared_request = Request(
|
|
64
|
-
|
|
65
|
-
self.__logger.debug(
|
|
66
|
-
f"Requesting data from geonames timezones: {prepared_request.url}")
|
|
101
|
+
prepared_request = Request("GET", self.timezone_url, params=params).prepare()
|
|
102
|
+
logger.debug("GeoNames timezone lookup url=%s", prepared_request.url)
|
|
67
103
|
|
|
68
104
|
try:
|
|
69
105
|
response = self.session.send(prepared_request)
|
|
70
106
|
response_json = response.json()
|
|
71
107
|
|
|
72
108
|
except Exception as e:
|
|
73
|
-
|
|
109
|
+
logger.error("GeoNames timezone request failed for %s: %s", self.timezone_url, e)
|
|
74
110
|
return {}
|
|
75
111
|
|
|
76
112
|
try:
|
|
77
|
-
timezone_data[
|
|
113
|
+
timezone_data["timezonestr"] = response_json["timezoneId"]
|
|
78
114
|
|
|
79
115
|
except Exception as e:
|
|
80
|
-
|
|
81
|
-
f"Error serializing data maybe wrong username? Details: {e}")
|
|
116
|
+
logger.error("GeoNames timezone payload missing expected keys: %s", e)
|
|
82
117
|
return {}
|
|
83
118
|
|
|
84
|
-
if hasattr(response,
|
|
85
|
-
timezone_data[
|
|
119
|
+
if hasattr(response, "from_cache"):
|
|
120
|
+
timezone_data["from_tz_cache"] = response.from_cache # type: ignore
|
|
86
121
|
|
|
87
122
|
return timezone_data
|
|
88
123
|
|
|
89
124
|
def __get_contry_data(self, city_name: str, country_code: str) -> dict[str, str]:
|
|
90
125
|
"""
|
|
91
|
-
Get
|
|
126
|
+
Get city location data without timezone for a given city and country.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
city_name: Name of the city to search for.
|
|
130
|
+
country_code: Two-letter country code.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
dict: City location data excluding timezone information.
|
|
92
134
|
"""
|
|
93
135
|
# Dictionary that will be returned:
|
|
94
136
|
city_data_whitout_tz = {}
|
|
95
137
|
|
|
96
138
|
params = {
|
|
97
139
|
"q": city_name,
|
|
98
|
-
"
|
|
140
|
+
"country": country_code,
|
|
99
141
|
"username": self.username,
|
|
100
142
|
"maxRows": 1,
|
|
101
|
-
"style": "
|
|
143
|
+
"style": "SHORT",
|
|
144
|
+
"featureClass": ["A", "P"],
|
|
102
145
|
}
|
|
103
146
|
|
|
104
|
-
prepared_request = Request(
|
|
105
|
-
|
|
106
|
-
self.__logger.debug(
|
|
107
|
-
f"Requesting data from geonames basic: {prepared_request.url}")
|
|
147
|
+
prepared_request = Request("GET", self.base_url, params=params).prepare()
|
|
148
|
+
logger.debug("GeoNames search url=%s", prepared_request.url)
|
|
108
149
|
|
|
109
150
|
try:
|
|
110
151
|
response = self.session.send(prepared_request)
|
|
152
|
+
response.raise_for_status()
|
|
111
153
|
response_json = response.json()
|
|
154
|
+
logger.debug("GeoNames search response: %s", response_json)
|
|
112
155
|
|
|
113
156
|
except Exception as e:
|
|
114
|
-
|
|
157
|
+
logger.error("GeoNames search request failed for %s: %s", self.base_url, e)
|
|
115
158
|
return {}
|
|
116
159
|
|
|
117
160
|
try:
|
|
118
|
-
city_data_whitout_tz[
|
|
119
|
-
city_data_whitout_tz[
|
|
120
|
-
city_data_whitout_tz[
|
|
121
|
-
city_data_whitout_tz[
|
|
161
|
+
city_data_whitout_tz["name"] = response_json["geonames"][0]["name"]
|
|
162
|
+
city_data_whitout_tz["lat"] = response_json["geonames"][0]["lat"]
|
|
163
|
+
city_data_whitout_tz["lng"] = response_json["geonames"][0]["lng"]
|
|
164
|
+
city_data_whitout_tz["countryCode"] = response_json["geonames"][0]["countryCode"]
|
|
122
165
|
|
|
123
166
|
except Exception as e:
|
|
124
|
-
|
|
125
|
-
f"Error serializing data maybe wrong username? Details: {e}")
|
|
167
|
+
logger.error("GeoNames search payload missing expected keys: %s", e)
|
|
126
168
|
return {}
|
|
127
169
|
|
|
128
|
-
if hasattr(response,
|
|
129
|
-
city_data_whitout_tz[
|
|
170
|
+
if hasattr(response, "from_cache"):
|
|
171
|
+
city_data_whitout_tz["from_country_cache"] = response.from_cache # type: ignore
|
|
130
172
|
|
|
131
173
|
return city_data_whitout_tz
|
|
132
174
|
|
|
133
175
|
def get_serialized_data(self) -> dict[str, str]:
|
|
134
176
|
"""
|
|
135
|
-
Returns all the data necessary for the Kerykeion calculation.
|
|
177
|
+
Returns all the data necessary for the Kerykeion calculation.
|
|
136
178
|
|
|
137
179
|
Returns:
|
|
138
180
|
dict[str, str]: _description_
|
|
139
181
|
"""
|
|
140
|
-
city_data_response = self.__get_contry_data(
|
|
141
|
-
self.city_name, self.country_code)
|
|
182
|
+
city_data_response = self.__get_contry_data(self.city_name, self.country_code)
|
|
142
183
|
try:
|
|
143
|
-
timezone_response = self.__get_timezone(
|
|
144
|
-
city_data_response['lat'], city_data_response['lng'])
|
|
184
|
+
timezone_response = self.__get_timezone(city_data_response["lat"], city_data_response["lng"])
|
|
145
185
|
|
|
146
186
|
except Exception as e:
|
|
147
|
-
|
|
187
|
+
logger.error("Unable to fetch timezone details: %s", e)
|
|
148
188
|
return {}
|
|
149
189
|
|
|
150
190
|
return {**timezone_response, **city_data_response}
|
|
151
191
|
|
|
152
192
|
|
|
153
193
|
if __name__ == "__main__":
|
|
154
|
-
|
|
194
|
+
"""Run a tiny demonstration when executing the module directly."""
|
|
195
|
+
from kerykeion.utilities import setup_logging as configure_logging
|
|
196
|
+
|
|
197
|
+
configure_logging("debug")
|
|
198
|
+
geonames = FetchGeonames("Montichiari", "IT")
|
|
155
199
|
print(geonames.get_serialized_data())
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
House Comparison Factory Module
|
|
3
|
+
|
|
4
|
+
Provides factory class for house comparison analysis between astrological subjects.
|
|
5
|
+
Enables bidirectional analysis of astrological point placements in house systems.
|
|
6
|
+
|
|
7
|
+
Author: Giacomo Battaglia
|
|
8
|
+
Copyright: (C) 2025 Kerykeion Project
|
|
9
|
+
License: AGPL-3.0
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from kerykeion.house_comparison.house_comparison_utils import calculate_points_in_reciprocal_houses
|
|
13
|
+
from typing import Union
|
|
14
|
+
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS
|
|
15
|
+
from kerykeion.schemas.kr_models import HouseComparisonModel
|
|
16
|
+
from kerykeion.astrological_subject_factory import AstrologicalSubjectFactory
|
|
17
|
+
from kerykeion.schemas import AstrologicalSubjectModel, PlanetReturnModel
|
|
18
|
+
from kerykeion.schemas.kr_literals import AstrologicalPoint
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class HouseComparisonFactory:
|
|
22
|
+
"""
|
|
23
|
+
Factory for creating house comparison analyses between two astrological subjects.
|
|
24
|
+
|
|
25
|
+
Analyzes placement of astrological points from one subject within the house system
|
|
26
|
+
of another subject, performing bidirectional analysis for synastry studies and
|
|
27
|
+
subject comparisons. Supports both natal subjects and planetary return subjects.
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
first_subject: First astrological subject (natal or return subject)
|
|
31
|
+
second_subject: Second astrological subject (natal or return subject)
|
|
32
|
+
active_points: List of astrological points to include in analysis
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
>>> natal_chart = AstrologicalSubjectFactory.from_birth_data(
|
|
36
|
+
... "Person A", 1990, 5, 15, 10, 30, "Rome", "IT"
|
|
37
|
+
... )
|
|
38
|
+
>>> partner_chart = AstrologicalSubjectFactory.from_birth_data(
|
|
39
|
+
... "Person B", 1992, 8, 23, 14, 45, "Milan", "IT"
|
|
40
|
+
... )
|
|
41
|
+
>>> factory = HouseComparisonFactory(natal_chart, partner_chart)
|
|
42
|
+
>>> comparison = factory.get_house_comparison()
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
def __init__(self,
|
|
46
|
+
first_subject: Union["AstrologicalSubjectModel", "PlanetReturnModel"],
|
|
47
|
+
second_subject: Union["AstrologicalSubjectModel", "PlanetReturnModel"],
|
|
48
|
+
active_points: list[AstrologicalPoint] = DEFAULT_ACTIVE_POINTS,
|
|
49
|
+
|
|
50
|
+
):
|
|
51
|
+
"""
|
|
52
|
+
Initialize the house comparison factory.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
first_subject: First astrological subject for comparison
|
|
56
|
+
second_subject: Second astrological subject for comparison
|
|
57
|
+
active_points: List of astrological points to include in analysis.
|
|
58
|
+
Defaults to standard active points.
|
|
59
|
+
|
|
60
|
+
Note:
|
|
61
|
+
Both subjects must have valid house system data for accurate analysis.
|
|
62
|
+
"""
|
|
63
|
+
self.first_subject = first_subject
|
|
64
|
+
self.second_subject = second_subject
|
|
65
|
+
self.active_points = active_points
|
|
66
|
+
|
|
67
|
+
def get_house_comparison(self) -> "HouseComparisonModel":
|
|
68
|
+
"""
|
|
69
|
+
Generate bidirectional house comparison analysis between the two subjects.
|
|
70
|
+
|
|
71
|
+
Calculates where each active astrological point from one subject falls within
|
|
72
|
+
the house system of the other subject, and vice versa.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
HouseComparisonModel: Model containing:
|
|
76
|
+
- first_subject_name: Name of the first subject
|
|
77
|
+
- second_subject_name: Name of the second subject
|
|
78
|
+
- first_points_in_second_houses: First subject's points in second subject's houses
|
|
79
|
+
- second_points_in_first_houses: Second subject's points in first subject's houses
|
|
80
|
+
|
|
81
|
+
Note:
|
|
82
|
+
Analysis scope is determined by the active_points list. Only specified
|
|
83
|
+
points will be included in the results.
|
|
84
|
+
"""
|
|
85
|
+
first_points_in_second_houses = calculate_points_in_reciprocal_houses(self.first_subject, self.second_subject, self.active_points)
|
|
86
|
+
second_points_in_first_houses = calculate_points_in_reciprocal_houses(self.second_subject, self.first_subject, self.active_points)
|
|
87
|
+
|
|
88
|
+
return HouseComparisonModel(
|
|
89
|
+
first_subject_name=self.first_subject.name,
|
|
90
|
+
second_subject_name=self.second_subject.name,
|
|
91
|
+
first_points_in_second_houses=first_points_in_second_houses,
|
|
92
|
+
second_points_in_first_houses=second_points_in_first_houses,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
if __name__ == "__main__":
|
|
97
|
+
natal_chart = AstrologicalSubjectFactory.from_birth_data("Person A", 1990, 5, 15, 10, 30, "Rome", "IT")
|
|
98
|
+
partner_chart = AstrologicalSubjectFactory.from_birth_data("Person B", 1992, 8, 23, 14, 45, "Milan", "IT")
|
|
99
|
+
|
|
100
|
+
factory = HouseComparisonFactory(natal_chart, partner_chart)
|
|
101
|
+
comparison = factory.get_house_comparison()
|
|
102
|
+
|
|
103
|
+
print(comparison.model_dump_json(indent=4))
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""
|
|
2
|
+
House Comparison Utilities
|
|
3
|
+
|
|
4
|
+
Utility functions for calculating house placement relationships between astrological subjects.
|
|
5
|
+
Provides core calculation logic for determining where points from one subject fall within
|
|
6
|
+
another subject's house system.
|
|
7
|
+
|
|
8
|
+
Author: Giacomo Battaglia
|
|
9
|
+
Copyright: (C) 2025 Kerykeion Project
|
|
10
|
+
License: AGPL-3.0
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from kerykeion.schemas.kr_models import AstrologicalSubjectModel, PlanetReturnModel, PointInHouseModel
|
|
14
|
+
from kerykeion.schemas.kr_literals import AstrologicalPoint
|
|
15
|
+
from kerykeion.settings.config_constants import DEFAULT_ACTIVE_POINTS
|
|
16
|
+
from kerykeion.utilities import get_planet_house, get_house_number
|
|
17
|
+
from typing import Union
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def calculate_points_in_reciprocal_houses(
|
|
21
|
+
point_subject: Union[AstrologicalSubjectModel, PlanetReturnModel],
|
|
22
|
+
house_subject: Union[AstrologicalSubjectModel, PlanetReturnModel],
|
|
23
|
+
active_points: list[AstrologicalPoint] = DEFAULT_ACTIVE_POINTS,
|
|
24
|
+
) -> list[PointInHouseModel]:
|
|
25
|
+
"""
|
|
26
|
+
Calculate house placements of one subject's points within another subject's house system.
|
|
27
|
+
|
|
28
|
+
Analyzes where each astrological point from the point_subject falls within the
|
|
29
|
+
house structure of the house_subject. Creates detailed mapping including both
|
|
30
|
+
the point's original house position and its projected house placement.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
point_subject: Subject whose astrological points are being analyzed
|
|
34
|
+
house_subject: Subject whose house system provides the projection framework
|
|
35
|
+
active_points: List of astrological points to include in the analysis.
|
|
36
|
+
Defaults to standard active points configuration.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
list[PointInHouseModel]: List of point placement models containing detailed
|
|
40
|
+
information about each point's house relationships,
|
|
41
|
+
including original and projected house positions.
|
|
42
|
+
|
|
43
|
+
Note:
|
|
44
|
+
Only processes points that exist in both the point_subject's active_points
|
|
45
|
+
and the provided active_points list. Points with None values are skipped.
|
|
46
|
+
|
|
47
|
+
Example:
|
|
48
|
+
>>> points_in_houses = calculate_points_in_reciprocal_houses(
|
|
49
|
+
... natal_chart, partner_chart, ["Sun", "Moon"]
|
|
50
|
+
... )
|
|
51
|
+
>>> sun_placement = points_in_houses[0] # Assuming Sun is first
|
|
52
|
+
>>> print(f"Sun falls in house: {sun_placement.projected_house_name}")
|
|
53
|
+
"""
|
|
54
|
+
points_in_houses: list[PointInHouseModel] = []
|
|
55
|
+
|
|
56
|
+
# List of points to consider
|
|
57
|
+
celestial_points = []
|
|
58
|
+
|
|
59
|
+
for point in point_subject.active_points:
|
|
60
|
+
if point not in active_points:
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
point_obj = getattr(point_subject, point.lower())
|
|
64
|
+
if point_obj is not None:
|
|
65
|
+
celestial_points.append(point_obj)
|
|
66
|
+
|
|
67
|
+
# Ordered list of house cusps degrees for house_subject
|
|
68
|
+
house_cusps = [
|
|
69
|
+
house_subject.first_house.abs_pos,
|
|
70
|
+
house_subject.second_house.abs_pos,
|
|
71
|
+
house_subject.third_house.abs_pos,
|
|
72
|
+
house_subject.fourth_house.abs_pos,
|
|
73
|
+
house_subject.fifth_house.abs_pos,
|
|
74
|
+
house_subject.sixth_house.abs_pos,
|
|
75
|
+
house_subject.seventh_house.abs_pos,
|
|
76
|
+
house_subject.eighth_house.abs_pos,
|
|
77
|
+
house_subject.ninth_house.abs_pos,
|
|
78
|
+
house_subject.tenth_house.abs_pos,
|
|
79
|
+
house_subject.eleventh_house.abs_pos,
|
|
80
|
+
house_subject.twelfth_house.abs_pos,
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
# Ordered list of house cusps degrees for point_subject
|
|
84
|
+
point_subject_house_cusps = [
|
|
85
|
+
point_subject.first_house.abs_pos,
|
|
86
|
+
point_subject.second_house.abs_pos,
|
|
87
|
+
point_subject.third_house.abs_pos,
|
|
88
|
+
point_subject.fourth_house.abs_pos,
|
|
89
|
+
point_subject.fifth_house.abs_pos,
|
|
90
|
+
point_subject.sixth_house.abs_pos,
|
|
91
|
+
point_subject.seventh_house.abs_pos,
|
|
92
|
+
point_subject.eighth_house.abs_pos,
|
|
93
|
+
point_subject.ninth_house.abs_pos,
|
|
94
|
+
point_subject.tenth_house.abs_pos,
|
|
95
|
+
point_subject.eleventh_house.abs_pos,
|
|
96
|
+
point_subject.twelfth_house.abs_pos,
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
# For each point, determine which house it falls in
|
|
100
|
+
for point in celestial_points:
|
|
101
|
+
if point is None:
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
point_degree = point.abs_pos
|
|
105
|
+
house_name = get_planet_house(point_degree, house_cusps)
|
|
106
|
+
house_number = get_house_number(house_name)
|
|
107
|
+
|
|
108
|
+
# Find which house the point is in its own chart (point_subject)
|
|
109
|
+
point_owner_house_name = get_planet_house(point_degree, point_subject_house_cusps)
|
|
110
|
+
point_owner_house_number = get_house_number(point_owner_house_name)
|
|
111
|
+
|
|
112
|
+
point_in_house = PointInHouseModel(
|
|
113
|
+
point_name=point.name,
|
|
114
|
+
point_degree=point.position,
|
|
115
|
+
point_sign=point.sign,
|
|
116
|
+
point_owner_name=point_subject.name,
|
|
117
|
+
point_owner_house_name=point_owner_house_name,
|
|
118
|
+
point_owner_house_number=point_owner_house_number,
|
|
119
|
+
projected_house_number=house_number,
|
|
120
|
+
projected_house_name=house_name,
|
|
121
|
+
projected_house_owner_name=house_subject.name,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
points_in_houses.append(point_in_house)
|
|
125
|
+
|
|
126
|
+
return points_in_houses
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Backward compatibility module for Kerykeion v4.x imports.
|
|
4
|
+
|
|
5
|
+
DEPRECATED: This module will be removed in Kerykeion v6.0.
|
|
6
|
+
Please update your imports:
|
|
7
|
+
OLD: from kerykeion.kr_types import ...
|
|
8
|
+
NEW: from kerykeion.schemas import ...
|
|
9
|
+
"""
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
# Issue deprecation warning when this module is imported
|
|
13
|
+
warnings.warn(
|
|
14
|
+
"The 'kerykeion.kr_types' module is deprecated and will be removed in v6.0. "
|
|
15
|
+
"Please update your imports to use 'kerykeion.schemas' instead.",
|
|
16
|
+
DeprecationWarning,
|
|
17
|
+
stacklevel=2,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# Re-export everything from schemas for backward compatibility
|
|
21
|
+
from kerykeion.schemas import * # noqa: F401, F403
|
|
22
|
+
from kerykeion.schemas.kerykeion_exception import * # noqa: F401, F403
|
|
23
|
+
from kerykeion.schemas.kr_literals import * # noqa: F401, F403
|
|
24
|
+
from kerykeion.schemas.kr_models import * # noqa: F401, F403
|
|
25
|
+
from kerykeion.schemas.settings_models import * # noqa: F401, F403
|
|
26
|
+
from kerykeion.schemas.chart_template_model import * # noqa: F401, F403
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
# Re-export from schemas
|
|
30
|
+
"KerykeionException",
|
|
31
|
+
# kr_literals
|
|
32
|
+
"ZodiacType",
|
|
33
|
+
"Sign",
|
|
34
|
+
"SignNumbers",
|
|
35
|
+
"AspectMovementType",
|
|
36
|
+
"Houses",
|
|
37
|
+
"HouseNumbers",
|
|
38
|
+
"AstrologicalPoint",
|
|
39
|
+
"Element",
|
|
40
|
+
"Quality",
|
|
41
|
+
"ChartType",
|
|
42
|
+
"PointType",
|
|
43
|
+
"LunarPhaseEmoji",
|
|
44
|
+
"LunarPhaseName",
|
|
45
|
+
"SiderealMode",
|
|
46
|
+
"HousesSystemIdentifier",
|
|
47
|
+
"PerspectiveType",
|
|
48
|
+
"SignsEmoji",
|
|
49
|
+
"KerykeionChartTheme",
|
|
50
|
+
"KerykeionChartLanguage",
|
|
51
|
+
"RelationshipScoreDescription",
|
|
52
|
+
"CompositeChartType",
|
|
53
|
+
"AspectName",
|
|
54
|
+
# kr_models
|
|
55
|
+
"AstrologicalSubjectModel",
|
|
56
|
+
"CompositeSubjectModel",
|
|
57
|
+
"KerykeionPointModel",
|
|
58
|
+
"AspectModel",
|
|
59
|
+
"ActiveAspect",
|
|
60
|
+
"SingleChartAspectsModel",
|
|
61
|
+
"DualChartAspectsModel",
|
|
62
|
+
"ElementDistributionModel",
|
|
63
|
+
"QualityDistributionModel",
|
|
64
|
+
"SingleChartDataModel",
|
|
65
|
+
"DualChartDataModel",
|
|
66
|
+
# settings_models
|
|
67
|
+
"KerykeionSettingsModel",
|
|
68
|
+
# chart_template_model
|
|
69
|
+
"ChartTemplateModel",
|
|
70
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Backward compatibility module for chart_template_model.
|
|
4
|
+
|
|
5
|
+
DEPRECATED: This module will be removed in Kerykeion v6.0.
|
|
6
|
+
Please update your imports:
|
|
7
|
+
OLD: from kerykeion.kr_types.chart_template_model import ...
|
|
8
|
+
NEW: from kerykeion.schemas.chart_template_model import ...
|
|
9
|
+
"""
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
warnings.warn(
|
|
13
|
+
"The 'kerykeion.kr_types.chart_template_model' module is deprecated and will be removed in v6.0. "
|
|
14
|
+
"Please update your imports to use 'kerykeion.schemas.chart_template_model' instead.",
|
|
15
|
+
DeprecationWarning,
|
|
16
|
+
stacklevel=2,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Re-export everything from schemas.chart_template_model for backward compatibility
|
|
20
|
+
from kerykeion.schemas.chart_template_model import * # noqa: F401, F403
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Backward compatibility module for kerykeion_exception.
|
|
4
|
+
|
|
5
|
+
DEPRECATED: This module will be removed in Kerykeion v6.0.
|
|
6
|
+
Please update your imports:
|
|
7
|
+
OLD: from kerykeion.kr_types.kerykeion_exception import ...
|
|
8
|
+
NEW: from kerykeion.schemas.kerykeion_exception import ...
|
|
9
|
+
"""
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
warnings.warn(
|
|
13
|
+
"The 'kerykeion.kr_types.kerykeion_exception' module is deprecated and will be removed in v6.0. "
|
|
14
|
+
"Please update your imports to use 'kerykeion.schemas.kerykeion_exception' instead.",
|
|
15
|
+
DeprecationWarning,
|
|
16
|
+
stacklevel=2,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Re-export everything from schemas.kerykeion_exception for backward compatibility
|
|
20
|
+
from kerykeion.schemas.kerykeion_exception import * # noqa: F401, F403
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Backward compatibility module for kr_literals.
|
|
4
|
+
|
|
5
|
+
DEPRECATED: This module will be removed in Kerykeion v6.0.
|
|
6
|
+
Please update your imports:
|
|
7
|
+
OLD: from kerykeion.kr_types.kr_literals import ...
|
|
8
|
+
NEW: from kerykeion.schemas.kr_literals import ...
|
|
9
|
+
"""
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
warnings.warn(
|
|
13
|
+
"The 'kerykeion.kr_types.kr_literals' module is deprecated and will be removed in v6.0. "
|
|
14
|
+
"Please update your imports to use 'kerykeion.schemas.kr_literals' instead.",
|
|
15
|
+
DeprecationWarning,
|
|
16
|
+
stacklevel=2,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Re-export everything from schemas.kr_literals for backward compatibility
|
|
20
|
+
from kerykeion.schemas.kr_literals import * # noqa: F401, F403
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Backward compatibility module for kr_models.
|
|
4
|
+
|
|
5
|
+
DEPRECATED: This module will be removed in Kerykeion v6.0.
|
|
6
|
+
Please update your imports:
|
|
7
|
+
OLD: from kerykeion.kr_types.kr_models import ...
|
|
8
|
+
NEW: from kerykeion.schemas.kr_models import ...
|
|
9
|
+
"""
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
warnings.warn(
|
|
13
|
+
"The 'kerykeion.kr_types.kr_models' module is deprecated and will be removed in v6.0. "
|
|
14
|
+
"Please update your imports to use 'kerykeion.schemas.kr_models' instead.",
|
|
15
|
+
DeprecationWarning,
|
|
16
|
+
stacklevel=2,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Re-export everything from schemas.kr_models for backward compatibility
|
|
20
|
+
from kerykeion.schemas.kr_models import * # noqa: F401, F403
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Backward compatibility module for settings_models.
|
|
4
|
+
|
|
5
|
+
DEPRECATED: This module will be removed in Kerykeion v6.0.
|
|
6
|
+
Please update your imports:
|
|
7
|
+
OLD: from kerykeion.kr_types.settings_models import ...
|
|
8
|
+
NEW: from kerykeion.schemas.settings_models import ...
|
|
9
|
+
"""
|
|
10
|
+
import warnings
|
|
11
|
+
|
|
12
|
+
warnings.warn(
|
|
13
|
+
"The 'kerykeion.kr_types.settings_models' module is deprecated and will be removed in v6.0. "
|
|
14
|
+
"Please update your imports to use 'kerykeion.schemas.settings_models' instead.",
|
|
15
|
+
DeprecationWarning,
|
|
16
|
+
stacklevel=2,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Re-export everything from schemas.settings_models for backward compatibility
|
|
20
|
+
from kerykeion.schemas.settings_models import * # noqa: F401, F403
|