kerykeion 4.11.1__tar.gz → 4.12.1__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.

Files changed (30) hide show
  1. {kerykeion-4.11.1 → kerykeion-4.12.1}/PKG-INFO +23 -5
  2. {kerykeion-4.11.1 → kerykeion-4.12.1}/README.md +21 -3
  3. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/aspects/synastry_aspects.py +2 -2
  4. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/astrological_subject.py +173 -111
  5. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/charts/kerykeion_chart_svg.py +40 -18
  6. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/charts/templates/chart.xml +6 -6
  7. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/kr_types/kr_literals.py +14 -2
  8. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/kr_types/kr_models.py +12 -2
  9. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/utilities.py +14 -0
  10. {kerykeion-4.11.1 → kerykeion-4.12.1}/pyproject.toml +2 -2
  11. {kerykeion-4.11.1 → kerykeion-4.12.1}/LICENSE +0 -0
  12. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/__init__.py +0 -0
  13. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/aspects/__init__.py +0 -0
  14. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/aspects/aspects_utils.py +0 -0
  15. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/aspects/natal_aspects.py +0 -0
  16. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/charts/__init__.py +0 -0
  17. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/charts/charts_utils.py +0 -0
  18. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/enums.py +0 -0
  19. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/fetch_geonames.py +0 -0
  20. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/kr_types/__init__.py +0 -0
  21. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/kr_types/chart_types.py +0 -0
  22. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/kr_types/kerykeion_exception.py +0 -0
  23. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/kr_types/settings_models.py +0 -0
  24. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/relationship_score.py +0 -0
  25. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/report.py +0 -0
  26. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/settings/__init__.py +0 -0
  27. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/settings/kerykeion_settings.py +0 -0
  28. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/settings/kr.config.json +0 -0
  29. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/sweph/README.md +0 -0
  30. {kerykeion-4.11.1 → kerykeion-4.12.1}/kerykeion/sweph/seas_18.se1 +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kerykeion
3
- Version: 4.11.1
3
+ Version: 4.12.1
4
4
  Summary: A python library for astrology.
5
- Home-page: https://github.com/g-battaglia/kerykeion
5
+ Home-page: https://www.kerykeion.net/
6
6
  License: AGPL-3.0
7
7
  Keywords: astrology,ephemeris,astrology library,birtchart,svg,zodiac,zodiac-sing,astronomical-algorithms,synastry,astrology-calculator
8
8
  Author: Giacomo Battaglia
@@ -142,7 +142,7 @@ If you omit the nation, it will be set to "GB" by default, but the value is not
142
142
  ```python
143
143
  from kerykeion import AstrologicalSubject, KerykeionChartSVG
144
144
 
145
- first = AstrologicalSubject("John Lennon", 1940, 10, 9, 10, 30, "Liverpool", "GB")
145
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
146
146
  second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
147
147
 
148
148
  # Set the type, it can be Natal, Synastry or Transit
@@ -153,13 +153,12 @@ synastry_chart.makeSVG()
153
153
 
154
154
  ![John Lennon and Paul McCartney Synastry](https://www.kerykeion.net/assets/img/examples/synastry-chart.svg)
155
155
 
156
-
157
156
  Note: By default, the generated SVG file will be in the home directory! To change the destination directory:
158
157
 
159
158
  ```python
160
159
  from kerykeion import AstrologicalSubject, KerykeionChartSVG
161
160
 
162
- first = AstrologicalSubject("John Lennon", 1940, 10, 9, 10, 30, "Liverpool", "GB")
161
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
163
162
  second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
164
163
 
165
164
  # Synastry Chart
@@ -167,6 +166,12 @@ synastry_chart = KerykeionChartSVG(first, "Synastry", second, new_output_directo
167
166
  synastry_chart.makeSVG()
168
167
  ```
169
168
 
169
+ ### Change Language
170
+
171
+ To change the language of the chart you should create a new kr.config.js file and pass it to the BirthChartSVG class. So far the available languages are English, Portuguese, Italian, Spanish, French and Chinese.
172
+
173
+ Some examples [here](https://www.kerykeion.net/docs/examples/change-language).
174
+
170
175
  ## Report
171
176
 
172
177
  To print a report of all the data:
@@ -276,6 +281,19 @@ Full list of supported house systems [here](https://www.kerykeion.net/pydocs/ker
276
281
 
277
282
  So far all the available houses system in the Swiss Ephemeris are supported but the Gauquelin Sectors.
278
283
 
284
+ ## Perspective Type
285
+
286
+ The perspective indicates the point of view from which the chart is calculated (Es. Apparent Geocentric, Heliocentric, etc.).
287
+ You can set the perspective type in the AstrologicalSubject class:
288
+
289
+ ```python
290
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="Heliocentric")
291
+ ```
292
+
293
+ More examples [here](https://www.kerykeion.net/docs/examples/perspective-type/).
294
+
295
+ Full list of supported perspective types [here](https://www.kerykeion.net/pydocs/kerykeion/kr_types/kr_literals.html#PerspectiveType).
296
+
279
297
  ## Documentation
280
298
 
281
299
  Most of the functions and the classes are self documented by the types and have docstrings.
@@ -105,7 +105,7 @@ If you omit the nation, it will be set to "GB" by default, but the value is not
105
105
  ```python
106
106
  from kerykeion import AstrologicalSubject, KerykeionChartSVG
107
107
 
108
- first = AstrologicalSubject("John Lennon", 1940, 10, 9, 10, 30, "Liverpool", "GB")
108
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
109
109
  second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
110
110
 
111
111
  # Set the type, it can be Natal, Synastry or Transit
@@ -116,13 +116,12 @@ synastry_chart.makeSVG()
116
116
 
117
117
  ![John Lennon and Paul McCartney Synastry](https://www.kerykeion.net/assets/img/examples/synastry-chart.svg)
118
118
 
119
-
120
119
  Note: By default, the generated SVG file will be in the home directory! To change the destination directory:
121
120
 
122
121
  ```python
123
122
  from kerykeion import AstrologicalSubject, KerykeionChartSVG
124
123
 
125
- first = AstrologicalSubject("John Lennon", 1940, 10, 9, 10, 30, "Liverpool", "GB")
124
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
126
125
  second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
127
126
 
128
127
  # Synastry Chart
@@ -130,6 +129,12 @@ synastry_chart = KerykeionChartSVG(first, "Synastry", second, new_output_directo
130
129
  synastry_chart.makeSVG()
131
130
  ```
132
131
 
132
+ ### Change Language
133
+
134
+ To change the language of the chart you should create a new kr.config.js file and pass it to the BirthChartSVG class. So far the available languages are English, Portuguese, Italian, Spanish, French and Chinese.
135
+
136
+ Some examples [here](https://www.kerykeion.net/docs/examples/change-language).
137
+
133
138
  ## Report
134
139
 
135
140
  To print a report of all the data:
@@ -239,6 +244,19 @@ Full list of supported house systems [here](https://www.kerykeion.net/pydocs/ker
239
244
 
240
245
  So far all the available houses system in the Swiss Ephemeris are supported but the Gauquelin Sectors.
241
246
 
247
+ ## Perspective Type
248
+
249
+ The perspective indicates the point of view from which the chart is calculated (Es. Apparent Geocentric, Heliocentric, etc.).
250
+ You can set the perspective type in the AstrologicalSubject class:
251
+
252
+ ```python
253
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="Heliocentric")
254
+ ```
255
+
256
+ More examples [here](https://www.kerykeion.net/docs/examples/perspective-type/).
257
+
258
+ Full list of supported perspective types [here](https://www.kerykeion.net/pydocs/kerykeion/kr_types/kr_literals.html#PerspectiveType).
259
+
242
260
  ## Documentation
243
261
 
244
262
  Most of the functions and the classes are self documented by the types and have docstrings.
@@ -95,8 +95,8 @@ if __name__ == "__main__":
95
95
  from kerykeion.utilities import setup_logging
96
96
  setup_logging(level="debug")
97
97
 
98
- john = AstrologicalSubject("John", 1940, 10, 9, 10, 30, "Liverpool")
99
- yoko = AstrologicalSubject("Yoko", 1933, 2, 18, 10, 30, "Tokyo")
98
+ john = AstrologicalSubject("John", 1940, 10, 9, 18, 30, "Liverpool")
99
+ yoko = AstrologicalSubject("Yoko", 1933, 2, 18, 18, 30, "Tokyo")
100
100
 
101
101
  synastry_aspects = SynastryAspects(john, yoko)
102
102
 
@@ -8,6 +8,7 @@ import swisseph as swe
8
8
  import logging
9
9
 
10
10
  from datetime import datetime
11
+ from functools import cached_property
11
12
  from kerykeion.fetch_geonames import FetchGeonames
12
13
  from kerykeion.kr_types import (
13
14
  KerykeionException,
@@ -17,7 +18,8 @@ from kerykeion.kr_types import (
17
18
  KerykeionPointModel,
18
19
  PointType,
19
20
  SiderealMode,
20
- HousesSystemIdentifier
21
+ HousesSystemIdentifier,
22
+ PerspectiveType
21
23
  )
22
24
  from kerykeion.utilities import (
23
25
  get_number_from_name,
@@ -25,6 +27,7 @@ from kerykeion.utilities import (
25
27
  get_planet_house,
26
28
  get_moon_emoji_from_phase_int,
27
29
  get_moon_phase_name_from_phase_int,
30
+ check_and_adjust_polar_latitude
28
31
  )
29
32
  from pathlib import Path
30
33
  from typing import Union, get_args
@@ -32,6 +35,8 @@ from typing import Union, get_args
32
35
  DEFAULT_GEONAMES_USERNAME = "century.boy"
33
36
  DEFAULT_SIDEREAL_MODE = "FAGAN_BRADLEY"
34
37
  DEFAULT_HOUSES_SYSTEM = "P"
38
+ PERSPECTIVE_TYPE = "Apparent Geocentric"
39
+ NOW = datetime.now()
35
40
 
36
41
 
37
42
  class AstrologicalSubject:
@@ -40,27 +45,25 @@ class AstrologicalSubject:
40
45
  it's utc and julian day and returns an object with all that data.
41
46
 
42
47
  Args:
43
- - name (str, optional): _ Defaults to "Now".
44
- - year (int, optional): _ Defaults to now.year.
45
- - month (int, optional): _ Defaults to now.month.
46
- - day (int, optional): _ Defaults to now.day.
47
- - hour (int, optional): _ Defaults to now.hour.
48
- - minute (int, optional): _ Defaults to now.minute.
48
+ - name (str, optional): The name of the subject. Defaults to "Now".
49
+ - year (int, optional): The year of birth. Defaults to the current year.
50
+ - month (int, optional): The month of birth. Defaults to the current month.
51
+ - day (int, optional): The day of birth. Defaults to the current day.
52
+ - hour (int, optional): The hour of birth. Defaults to the current hour.
53
+ - minute (int, optional): Defaults to the current minute.
49
54
  - city (str, optional): City or location of birth. Defaults to "London", which is GMT time.
50
55
  The city argument is used to get the coordinates and timezone from geonames just in case
51
56
  you don't insert them manually (see _get_tz).
52
57
  If you insert the coordinates and timezone manually, the city argument is not used for calculations
53
58
  but it's still used as a value for the city attribute.
54
59
  - nat (str, optional): _ Defaults to "".
55
- - lng (Union[int, float], optional): _ Defaults to False.
56
- - lat (Union[int, float], optional): _ Defaults to False.
57
- - tz_str (Union[str, bool], optional): _ Defaults to False.
58
- - geonames_username (str, optional): _ Defaults to 'century.boy'.
59
- - online (bool, optional): Sets if you want to use the online mode (using
60
- geonames) or not. Defaults to True.
61
- - utc_datetime (datetime, optional): An alternative way of constructing the object,
62
- if you know the UTC datetime but do not have easy access to e.g. timezone identifier
63
- _ Defaults to None.
60
+ - lng (Union[int, float], optional): Longitude of the birth location. Defaults to 0 (Greenwich, London).
61
+ - lat (Union[int, float], optional): Latitude of the birth location. Defaults to 51.5074 (Greenwich, London).
62
+ - tz_str (Union[str, bool], optional): Timezone of the birth location. Defaults to "GMT".
63
+ - geonames_username (str, optional): The username for the geonames API. Note: Change this to your own username to avoid rate limits!
64
+ You can get one for free here: https://www.geonames.org/login
65
+ - online (bool, optional): Sets if you want to use the online mode, which fetches the timezone and coordinates from geonames.
66
+ If you already have the coordinates and timezone, set this to False. Defaults to True.
64
67
  - disable_chiron (bool, optional): Disables the calculation of Chiron. Defaults to False.
65
68
  Chiron calculation can create some issues with the Swiss Ephemeris when the date is too far in the past.
66
69
  - sidereal_mode (SiderealMode, optional): Also known as Ayanamsa.
@@ -68,11 +71,15 @@ class AstrologicalSubject:
68
71
  Defaults to "FAGAN_BRADLEY".
69
72
  Available modes are visible in the SiderealMode Literal.
70
73
  - houses_system_identifier (HousesSystemIdentifier, optional): The system to use for the calculation of the houses.
74
+ Defaults to "P" (Placidus).
75
+ Available systems are visible in the HousesSystemIdentifier Literal.
76
+ - perspective_type (PerspectiveType, optional): The perspective to use for the calculation of the chart.
77
+ Defaults to "Apparent Geocentric".
78
+ Available perspectives are visible in the PerspectiveType Literal.
71
79
  """
72
80
 
73
81
  # Defined by the user
74
82
  name: str
75
- utc_datetime: Union[datetime, None]
76
83
  year: int
77
84
  month: int
78
85
  day: int
@@ -89,14 +96,14 @@ class AstrologicalSubject:
89
96
  sidereal_mode: SiderealMode
90
97
  houses_system_identifier: HousesSystemIdentifier
91
98
  houses_system_name: str
99
+ perspective_type: PerspectiveType
92
100
 
93
101
  # Generated internally
94
102
  city_data: dict[str, str]
95
103
  julian_day: Union[int, float]
96
- utc_time: float
97
- local_time: float
98
- utc: datetime
99
104
  json_dir: Path
105
+ iso_formatted_local_datetime: str
106
+ iso_formatted_utc_datetime: str
100
107
 
101
108
  # Planets
102
109
  sun: KerykeionPointModel
@@ -133,16 +140,14 @@ class AstrologicalSubject:
133
140
  planets_degrees_ut: list[float]
134
141
  houses_degree_ut: list[float]
135
142
 
136
- now = datetime.now()
137
-
138
143
  def __init__(
139
144
  self,
140
145
  name="Now",
141
- year: int = now.year,
142
- month: int = now.month,
143
- day: int = now.day,
144
- hour: int = now.hour,
145
- minute: int = now.minute,
146
+ year: int = NOW.year,
147
+ month: int = NOW.month,
148
+ day: int = NOW.day,
149
+ hour: int = NOW.hour,
150
+ minute: int = NOW.minute,
146
151
  city: Union[str, None] = None,
147
152
  nation: Union[str, None] = None,
148
153
  lng: Union[int, float, None] = None,
@@ -151,19 +156,13 @@ class AstrologicalSubject:
151
156
  geonames_username: Union[str, None] = None,
152
157
  zodiac_type: ZodiacType = "Tropic",
153
158
  online: bool = True,
154
- utc_datetime: Union[datetime, None] = None,
155
159
  disable_chiron: bool = False,
156
160
  sidereal_mode: Union[SiderealMode, None] = None,
157
- houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM
161
+ houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM,
162
+ perspective_type: PerspectiveType = PERSPECTIVE_TYPE
158
163
  ) -> None:
159
164
  logging.debug("Starting Kerykeion")
160
165
 
161
- # We set the swisseph path to the current directory
162
- swe.set_ephe_path(str(Path(__file__).parent.absolute() / "sweph"))
163
-
164
- # Flags for the Swiss Ephemeris
165
- self._iflag = swe.FLG_SWIEPH + swe.FLG_SPEED
166
-
167
166
  self.name = name
168
167
  self.year = year
169
168
  self.month = month
@@ -179,39 +178,14 @@ class AstrologicalSubject:
179
178
  self.online = online
180
179
  self.json_dir = Path.home()
181
180
  self.geonames_username = geonames_username
182
- self.utc_datetime = utc_datetime
183
181
  self.disable_chiron = disable_chiron
184
182
  self.sidereal_mode = sidereal_mode
185
183
  self.houses_system_identifier = houses_system_identifier
184
+ self.perspective_type = perspective_type
186
185
 
187
- # House System check and setup --->
188
- if self.houses_system_identifier not in get_args(HousesSystemIdentifier):
189
- raise KerykeionException(f"\n* ERROR: '{self.houses_system_identifier}' is NOT a valid house system! Available systems are: *" + "\n" + str(get_args(HousesSystemIdentifier)))
190
-
191
- self.houses_system_name = swe.house_name(self.houses_system_identifier.encode('ascii'))
192
- # <--- House System check and setup
193
-
194
- # Zodiac Type and Sidereal mode checks and setup --->
195
- if zodiac_type and not zodiac_type in get_args(ZodiacType):
196
- raise KerykeionException(f"\n* ERROR: '{zodiac_type}' is NOT a valid zodiac type! Available types are: *" + "\n" + str(get_args(ZodiacType)))
197
-
198
- if self.sidereal_mode and self.zodiac_type == "Tropic":
199
- raise KerykeionException("You can't set a sidereal mode with a Tropic zodiac type!")
200
-
201
- if self.zodiac_type == "Sidereal" and not self.sidereal_mode:
202
- self.sidereal_mode = DEFAULT_SIDEREAL_MODE
203
- logging.info("No sidereal mode set, using default FAGAN_BRADLEY")
204
-
205
- if self.zodiac_type == "Sidereal":
206
- # Check if the sidereal mode is valid
207
- if not self.sidereal_mode in get_args(SiderealMode):
208
- raise KerykeionException(f"\n* ERROR: '{self.sidereal_mode}' is NOT a valid sidereal mode! Available modes are: *" + "\n" + str(get_args(SiderealMode)))
209
-
210
- self._iflag += swe.FLG_SIDEREAL
211
- mode = "SIDM_" + self.sidereal_mode
212
- swe.set_sid_mode(getattr(swe, mode))
213
- logging.debug(f"Using sidereal mode: {mode}")
214
- # <--- Zodiac Type and Sidereal mode checks and setup
186
+ #---------------#
187
+ # General setup #
188
+ #---------------#
215
189
 
216
190
  # This message is set to encourage the user to set a custom geonames username
217
191
  if geonames_username is None and online:
@@ -253,23 +227,99 @@ class AstrologicalSubject:
253
227
  if (not self.online) and (not tz_str):
254
228
  raise KerykeionException("You need to set the coordinates and timezone if you want to use the offline mode!")
255
229
 
256
- self._check_if_poles()
230
+ #-----------------------#
231
+ # Swiss Ephemeris setup #
232
+ #-----------------------#
233
+
234
+ # We set the swisseph path to the current directory
235
+ swe.set_ephe_path(str(Path(__file__).parent.absolute() / "sweph"))
236
+
237
+ # Flags for the Swiss Ephemeris
238
+ self._iflag = swe.FLG_SWIEPH + swe.FLG_SPEED
239
+
240
+ # Chart Perspective check and setup --->
241
+ if self.perspective_type not in get_args(PerspectiveType):
242
+ raise KerykeionException(f"\n* ERROR: '{self.perspective_type}' is NOT a valid chart perspective! Available perspectives are: *" + "\n" + str(get_args(PerspectiveType)))
243
+
244
+ if self.perspective_type == "True Geocentric":
245
+ self._iflag += swe.FLG_TRUEPOS
246
+ elif self.perspective_type == "Heliocentric":
247
+ self._iflag += swe.FLG_HELCTR
248
+ elif self.perspective_type == "Topocentric":
249
+ self._iflag += swe.FLG_TOPOCTR
250
+ # geopos_is_set, for topocentric
251
+ swe.set_topo(self.lng, self.lat, 0)
252
+ # <--- Chart Perspective check and setup
253
+
254
+ # House System check and setup --->
255
+ if self.houses_system_identifier not in get_args(HousesSystemIdentifier):
256
+ raise KerykeionException(f"\n* ERROR: '{self.houses_system_identifier}' is NOT a valid house system! Available systems are: *" + "\n" + str(get_args(HousesSystemIdentifier)))
257
+
258
+ self.houses_system_name = swe.house_name(self.houses_system_identifier.encode('ascii'))
259
+ # <--- House System check and setup
260
+
261
+ # Zodiac Type and Sidereal mode checks and setup --->
262
+ if zodiac_type and not zodiac_type in get_args(ZodiacType):
263
+ raise KerykeionException(f"\n* ERROR: '{zodiac_type}' is NOT a valid zodiac type! Available types are: *" + "\n" + str(get_args(ZodiacType)))
264
+
265
+ if self.sidereal_mode and self.zodiac_type == "Tropic":
266
+ raise KerykeionException("You can't set a sidereal mode with a Tropic zodiac type!")
267
+
268
+ if self.zodiac_type == "Sidereal" and not self.sidereal_mode:
269
+ self.sidereal_mode = DEFAULT_SIDEREAL_MODE
270
+ logging.info("No sidereal mode set, using default FAGAN_BRADLEY")
271
+
272
+ if self.zodiac_type == "Sidereal":
273
+ # Check if the sidereal mode is valid
274
+ if not self.sidereal_mode in get_args(SiderealMode):
275
+ raise KerykeionException(f"\n* ERROR: '{self.sidereal_mode}' is NOT a valid sidereal mode! Available modes are: *" + "\n" + str(get_args(SiderealMode)))
276
+
277
+ self._iflag += swe.FLG_SIDEREAL
278
+ mode = "SIDM_" + self.sidereal_mode
279
+ swe.set_sid_mode(getattr(swe, mode))
280
+ logging.debug(f"Using sidereal mode: {mode}")
281
+ # <--- Zodiac Type and Sidereal mode checks and setup
282
+
283
+ #------------------------#
284
+ # Start the calculations #
285
+ #------------------------#
286
+
287
+ check_and_adjust_polar_latitude(self.lat, self.lng)
288
+
289
+ # UTC, julian day and local time setup --->
290
+ if (self.online) and (not self.tz_str):
291
+ self._fetch_tz_from_geonames()
292
+
293
+ # Local time to UTC
294
+ local_time = pytz.timezone(self.tz_str)
295
+ naive_datetime = datetime(self.year, self.month, self.day, self.hour, self.minute, 0)
296
+ local_datetime = local_time.localize(naive_datetime, is_dst=None)
297
+ utc_object = local_datetime.astimezone(pytz.utc)
298
+ self.iso_formatted_utc_datetime = utc_object.isoformat()
299
+
300
+ # ISO formatted local datetime
301
+ self.iso_formatted_local_datetime = local_datetime.isoformat()
302
+
303
+ # Julian day calculation
304
+ utc_float_hour_with_minutes = utc_object.hour + (utc_object.minute / 60)
305
+ self.julian_day = float(swe.julday(utc_object.year, utc_object.month, utc_object.day, utc_float_hour_with_minutes))
306
+ # <--- UTC, julian day and local time setup
257
307
 
258
- # Initialize everything
259
- self._get_utc()
260
- self._get_jd()
261
308
  self._planets_degrees_lister()
262
309
  self._planets()
263
310
  self._houses()
264
-
265
311
  self._planets_in_houses()
266
312
  self._lunar_phase_calc()
267
313
 
314
+ # Deprecated properties
315
+ self.utc_time
316
+ self.local_time
317
+
268
318
  def __str__(self) -> str:
269
- return f"Astrological data for: {self.name}, {self.utc} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
319
+ return f"Astrological data for: {self.name}, {self.iso_formatted_utc_datetime} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
270
320
 
271
321
  def __repr__(self) -> str:
272
- return f"Astrological data for: {self.name}, {self.utc} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
322
+ return f"Astrological data for: {self.name}, {self.iso_formatted_utc_datetime} UTC\nBirth location: {self.city}, Lat {self.lat}, Lon {self.lng}"
273
323
 
274
324
  def __getitem__(self, item):
275
325
  return getattr(self, item)
@@ -301,32 +351,7 @@ class AstrologicalSubject:
301
351
  self.lat = float(self.city_data["lat"])
302
352
  self.tz_str = self.city_data["timezonestr"]
303
353
 
304
- self._check_if_poles()
305
-
306
- def _get_utc(self) -> None:
307
- """Converts local time to utc time."""
308
-
309
- # If the coordinates are not set, get them from geonames.
310
- if (self.online) and (not self.tz_str):
311
- self._fetch_tz_from_geonames()
312
-
313
- # If UTC datetime is provided, then use it directly
314
- if (self.utc_datetime):
315
- self.utc = self.utc_datetime
316
- return
317
-
318
- local_time = pytz.timezone(self.tz_str)
319
-
320
- naive_datetime = datetime(self.year, self.month, self.day, self.hour, self.minute, 0)
321
-
322
- local_datetime = local_time.localize(naive_datetime, is_dst=None)
323
- self.utc = local_datetime.astimezone(pytz.utc)
324
-
325
- def _get_jd(self) -> None:
326
- """Calculates julian day from the utc time."""
327
- self.utc_time = self.utc.hour + self.utc.minute / 60
328
- self.local_time = self.hour + self.minute / 60
329
- self.julian_day = float(swe.julday(self.utc.year, self.utc.month, self.utc.day, self.utc_time))
354
+ check_and_adjust_polar_latitude(self.lat, self.lng)
330
355
 
331
356
  def _houses(self) -> None:
332
357
  """
@@ -595,19 +620,6 @@ class AstrologicalSubject:
595
620
 
596
621
  self.lunar_phase = LunarPhaseModel(**lunar_phase_dictionary)
597
622
 
598
- def _check_if_poles(self):
599
- """
600
- Utility function to check if the location is in the polar circle.
601
- If it is, it sets the latitude to 66 or -66 degrees.
602
- """
603
- if self.lat > 66.0:
604
- self.lat = 66.0
605
- logging.info("Polar circle override for houses, using 66 degrees")
606
-
607
- elif self.lat < -66.0:
608
- self.lat = -66.0
609
- logging.info("Polar circle override for houses, using -66 degrees")
610
-
611
623
  def json(self, dump=False, destination_folder: Union[str, None] = None, indent: Union[int, None] = None) -> str:
612
624
  """
613
625
  Dumps the Kerykeion object to a json string foramt,
@@ -639,6 +651,41 @@ class AstrologicalSubject:
639
651
 
640
652
  return AstrologicalSubjectModel(**self.__dict__)
641
653
 
654
+ @cached_property
655
+ def utc_time(self) -> float:
656
+ """
657
+ Deprecated property, use iso_formatted_utc_datetime instead, will be removed in the future.
658
+ Returns the UTC time as a float.
659
+ """
660
+ dt = datetime.fromisoformat(self.iso_formatted_utc_datetime)
661
+
662
+ # Extract the hours, minutes, and seconds
663
+ hours = dt.hour
664
+ minutes = dt.minute
665
+ seconds = dt.second + dt.microsecond / 1_000_000
666
+
667
+ # Convert time to float hours
668
+ float_time = hours + minutes / 60 + seconds / 3600
669
+
670
+ return float_time
671
+
672
+ @cached_property
673
+ def local_time(self) -> float:
674
+ """
675
+ Deprecated property, use iso_formatted_local_datetime instead, will be removed in the future.
676
+ Returns the local time as a float.
677
+ """
678
+ dt = datetime.fromisoformat(self.iso_formatted_local_datetime)
679
+
680
+ # Extract the hours, minutes, and seconds
681
+ hours = dt.hour
682
+ minutes = dt.minute
683
+ seconds = dt.second + dt.microsecond / 1_000_000
684
+
685
+ # Convert time to float hours
686
+ float_time = hours + minutes / 60 + seconds / 3600
687
+
688
+ return float_time
642
689
 
643
690
  if __name__ == "__main__":
644
691
  import json
@@ -666,4 +713,19 @@ if __name__ == "__main__":
666
713
 
667
714
  # With Morinus Houses
668
715
  johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", houses_system_identifier="M")
669
- print(johnny.json(dump=True, indent=2))
716
+ print(johnny.json(dump=True, indent=2))
717
+
718
+ # With True Geocentric Perspective
719
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="True Geocentric")
720
+ print(johnny.json(dump=True, indent=2))
721
+
722
+ # With Heliocentric Perspective
723
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="Heliocentric")
724
+ print(johnny.json(dump=True, indent=2))
725
+
726
+ # With Topocentric Perspective
727
+ johnny = AstrologicalSubject("Johnny Depp", 1963, 6, 9, 0, 0, "Owensboro", "US", perspective_type="Topocentric")
728
+
729
+ # Print the utc time
730
+ print(johnny.utc_time)
731
+ print(johnny.local_time)
@@ -33,6 +33,7 @@ from pathlib import Path
33
33
  from scour.scour import scourString
34
34
  from string import Template
35
35
  from typing import Union, List
36
+ from datetime import datetime
36
37
 
37
38
 
38
39
 
@@ -1017,7 +1018,7 @@ class KerykeionChartSVG:
1017
1018
  li = 10
1018
1019
  offset = 0
1019
1020
 
1020
- out = '<g transform="translate(500,-20)">'
1021
+ out = '<g transform="translate(510,-20)">'
1021
1022
  out += '<g transform="translate(140, -15)">'
1022
1023
  out += f'<text text-anchor="end" style="fill:{self.chart_colors_settings["paper_0"]}; font-size: 14px;">{self.language_settings["planets_and_house"]} {self.user.name}:</text>'
1023
1024
  out += "</g>"
@@ -1108,7 +1109,7 @@ class KerykeionChartSVG:
1108
1109
  Returns:
1109
1110
  str: The SVG code for the grid of houses.
1110
1111
  """
1111
- out = '<g transform="translate(600,-20)">'
1112
+ out = '<g transform="translate(610,-20)">'
1112
1113
 
1113
1114
  li = 10
1114
1115
  for i in range(12):
@@ -1126,8 +1127,10 @@ class KerykeionChartSVG:
1126
1127
  out += "</g>"
1127
1128
 
1128
1129
  if self.chart_type == "Synastry":
1129
- out += '<g transform="translate(840, -20)">'
1130
+ out += '<!-- Synastry Houses -->'
1131
+ out += '<g transform="translate(850, -20)">'
1130
1132
  li = 10
1133
+
1131
1134
  for i in range(12):
1132
1135
  if i < 9:
1133
1136
  cusp = "&#160;&#160;" + str(i + 1)
@@ -1236,16 +1239,16 @@ class KerykeionChartSVG:
1236
1239
  if self.chart_type == "Natal" or self.chart_type == "ExternalNatal" or self.chart_type == "Synastry":
1237
1240
  td["bottomLeft0"] = f"{self.user.zodiac_type if self.user.zodiac_type == 'Tropic' else self.user.zodiac_type + ' ' + self.user.sidereal_mode}"
1238
1241
  td["bottomLeft1"] = f"{self.user.houses_system_name}"
1239
- td["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.user.lunar_phase.moon_phase_name}'
1240
- td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.user.lunar_phase.get("moon_phase", "")}'
1241
- td["bottomLeft4"] = ""
1242
+ td["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.user.lunar_phase.get("moon_phase", "")}'
1243
+ td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.user.lunar_phase.moon_phase_name}'
1244
+ td["bottomLeft4"] = f'{self.user.perspective_type}'
1242
1245
 
1243
1246
  else:
1244
1247
  td["bottomLeft0"] = f"{self.user.zodiac_type if self.user.zodiac_type == 'Tropic' else self.user.zodiac_type + ' ' + self.user.sidereal_mode}"
1245
1248
  td["bottomLeft1"] = f"{self.user.houses_system_name}"
1246
- td["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.t_user.lunar_phase.moon_phase_name}'
1247
- td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.t_user.lunar_phase.get("moon_phase", "")}'
1248
- td["bottomLeft4"] = ""
1249
+ td["bottomLeft2"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.language_settings.get("day", "Day")} {self.t_user.lunar_phase.get("moon_phase", "")}'
1250
+ td["bottomLeft3"] = f'{self.language_settings.get("lunar_phase", "Lunar Phase")}: {self.t_user.lunar_phase.moon_phase_name}'
1251
+ td["bottomLeft4"] = f'{self.t_user.perspective_type}'
1249
1252
 
1250
1253
  # lunar phase
1251
1254
  deg = self.user.lunar_phase["degrees_between_s_m"]
@@ -1313,8 +1316,6 @@ class KerykeionChartSVG:
1313
1316
  else:
1314
1317
  td["stringLocation"] = self.location
1315
1318
 
1316
- td["stringDateTime"] = f"{self.user.year}-{self.user.month}-{self.user.day} {self.user.hour:02d}:{self.user.minute:02d}"
1317
-
1318
1319
  if self.chart_type == "Synastry":
1319
1320
  td["stringLat"] = f"{self.t_user.name}: "
1320
1321
  td["stringLon"] = self.t_user.city
@@ -1378,6 +1379,12 @@ class KerykeionChartSVG:
1378
1379
  )
1379
1380
  td["makePlanetGrid"] = self._makePlanetGrid()
1380
1381
 
1382
+ # Date time String
1383
+ dt = datetime.fromisoformat(self.user.iso_formatted_local_datetime)
1384
+ custom_format = dt.strftime('%Y-%-m-%-d %H:%M [%z]') # Note the use of '-' to remove leading zeros
1385
+ custom_format = custom_format[:-3] + ':' + custom_format[-3:]
1386
+ td["stringDateTime"] = f"{custom_format}"
1387
+
1381
1388
  return td
1382
1389
 
1383
1390
  def makeTemplate(self, minify: bool = False) -> str:
@@ -1420,7 +1427,7 @@ if __name__ == "__main__":
1420
1427
  from kerykeion.utilities import setup_logging
1421
1428
  setup_logging(level="debug")
1422
1429
 
1423
- first = AstrologicalSubject("John Lennon", 1940, 10, 9, 10, 30, "Liverpool", "GB")
1430
+ first = AstrologicalSubject("John Lennon", 1940, 10, 9, 18, 30, "Liverpool", "GB")
1424
1431
  second = AstrologicalSubject("Paul McCartney", 1942, 6, 18, 15, 30, "Liverpool", "GB")
1425
1432
 
1426
1433
  # Internal Natal Chart
@@ -1440,27 +1447,27 @@ if __name__ == "__main__":
1440
1447
  transits_chart.makeSVG()
1441
1448
 
1442
1449
  # Sidereal Birth Chart (Lahiri)
1443
- sidereal_subject = AstrologicalSubject("John Lennon Lahiri", 1940, 10, 9, 10, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="LAHIRI")
1450
+ sidereal_subject = AstrologicalSubject("John Lennon Lahiri", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="LAHIRI")
1444
1451
  sidereal_chart = KerykeionChartSVG(sidereal_subject)
1445
1452
  sidereal_chart.makeSVG()
1446
1453
 
1447
1454
  # Sidereal Birth Chart (Fagan-Bradley)
1448
- sidereal_subject = AstrologicalSubject("John Lennon Fagan-Bradley", 1940, 10, 9, 10, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="FAGAN_BRADLEY")
1455
+ sidereal_subject = AstrologicalSubject("John Lennon Fagan-Bradley", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="FAGAN_BRADLEY")
1449
1456
  sidereal_chart = KerykeionChartSVG(sidereal_subject)
1450
1457
  sidereal_chart.makeSVG()
1451
1458
 
1452
1459
  # Sidereal Birth Chart (DeLuce)
1453
- sidereal_subject = AstrologicalSubject("John Lennon DeLuce", 1940, 10, 9, 10, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="DELUCE")
1460
+ sidereal_subject = AstrologicalSubject("John Lennon DeLuce", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="DELUCE")
1454
1461
  sidereal_chart = KerykeionChartSVG(sidereal_subject)
1455
1462
  sidereal_chart.makeSVG()
1456
1463
 
1457
1464
  # Sidereal Birth Chart (J2000)
1458
- sidereal_subject = AstrologicalSubject("John Lennon J2000", 1940, 10, 9, 10, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="J2000")
1465
+ sidereal_subject = AstrologicalSubject("John Lennon J2000", 1940, 10, 9, 18, 30, "Liverpool", "GB", zodiac_type="Sidereal", sidereal_mode="J2000")
1459
1466
  sidereal_chart = KerykeionChartSVG(sidereal_subject)
1460
1467
  sidereal_chart.makeSVG()
1461
1468
 
1462
1469
  # House System Morinus
1463
- morinus_house_subject = AstrologicalSubject("John Lennon - House System Morinus", 1940, 10, 9, 10, 30, "Liverpool", "GB", houses_system_identifier="M")
1470
+ morinus_house_subject = AstrologicalSubject("John Lennon - House System Morinus", 1940, 10, 9, 18, 30, "Liverpool", "GB", houses_system_identifier="M")
1464
1471
  morinus_house_chart = KerykeionChartSVG(morinus_house_subject)
1465
1472
  morinus_house_chart.makeSVG()
1466
1473
 
@@ -1468,6 +1475,21 @@ if __name__ == "__main__":
1468
1475
  # from kerykeion.kr_types import HousesSystemIdentifier
1469
1476
  # from typing import get_args
1470
1477
  # for i in get_args(HousesSystemIdentifier):
1471
- # alternatives_house_subject = AstrologicalSubject(f"John Lennon - House System {i}", 1940, 10, 9, 10, 30, "Liverpool", "GB", houses_system=i)
1478
+ # alternatives_house_subject = AstrologicalSubject(f"John Lennon - House System {i}", 1940, 10, 9, 18, 30, "Liverpool", "GB", houses_system=i)
1472
1479
  # alternatives_house_chart = KerykeionChartSVG(alternatives_house_subject)
1473
1480
  # alternatives_house_chart.makeSVG()
1481
+
1482
+ # With True Geocentric Perspective
1483
+ true_geocentric_subject = AstrologicalSubject("John Lennon - True Geocentric", 1940, 10, 9, 18, 30, "Liverpool", "GB", perspective_type="True Geocentric")
1484
+ true_geocentric_chart = KerykeionChartSVG(true_geocentric_subject)
1485
+ true_geocentric_chart.makeSVG()
1486
+
1487
+ # With Heliocentric Perspective
1488
+ heliocentric_subject = AstrologicalSubject("John Lennon - Heliocentric", 1940, 10, 9, 18, 30, "Liverpool", "GB", perspective_type="Heliocentric")
1489
+ heliocentric_chart = KerykeionChartSVG(heliocentric_subject)
1490
+ heliocentric_chart.makeSVG()
1491
+
1492
+ # With Topocentric Perspective
1493
+ topocentric_subject = AstrologicalSubject("John Lennon - Topocentric", 1940, 10, 9, 18, 30, "Liverpool", "GB", perspective_type="Topocentric")
1494
+ topocentric_chart = KerykeionChartSVG(topocentric_subject)
1495
+ topocentric_chart.makeSVG()
@@ -14,18 +14,18 @@
14
14
  <g transform="scale($cfgZoom)">
15
15
  <rect class="background-rectangle" x="0" y="0" width="$chart_width"
16
16
  height="$chart_height" style="fill: $paper_color_1" />
17
- <text x="20" y="30" style="fill: $paper_color_0; font-size: 24px">$stringTitle</text>
17
+ <text x="20" y="22" style="fill: $paper_color_0; font-size: 24px">$stringTitle</text>
18
18
  <text x="20" y="50" style="fill: $paper_color_0; font-size: 11px">$stringName</text>
19
19
  <text x="20" y="62" style="fill: $paper_color_0; font-size: 11px">$stringLocation</text>
20
20
  <text x="20" y="74" style="fill: $paper_color_0; font-size: 11px">$stringDateTime</text>
21
21
  <text x="20" y="86" style="fill: $paper_color_0; font-size: 11px">$stringLat</text>
22
22
  <text x="20" y="98" style="fill: $paper_color_0; font-size: 11px">$stringLon</text>
23
23
  <text x="20" y="110" style="fill: $paper_color_0; font-size: 11px">$stringPosition</text>
24
- <text x="20" y="466" style="fill: $paper_color_0; font-size: 10px">$bottomLeft0</text>
25
- <text x="20" y="480" style="fill: $paper_color_0; font-size: 10px">$bottomLeft1</text>
26
- <text x="20" y="494" style="fill: $paper_color_0; font-size: 10px">$bottomLeft2</text>
27
- <text x="20" y="508" style="fill: $paper_color_0; font-size: 10px">$bottomLeft3</text>
28
- <text x="20" y="522" style="fill: $paper_color_0; font-size: 10px">$bottomLeft4</text>
24
+ <text x="20" y="452" style="fill: $paper_color_0; font-size: 10px">$bottomLeft0</text>
25
+ <text x="20" y="466" style="fill: $paper_color_0; font-size: 10px">$bottomLeft1</text>
26
+ <text x="20" y="480" style="fill: $paper_color_0; font-size: 10px">$bottomLeft2</text>
27
+ <text x="20" y="494" style="fill: $paper_color_0; font-size: 10px">$bottomLeft3</text>
28
+ <text x="20" y="508" style="fill: $paper_color_0; font-size: 10px">$bottomLeft4</text>
29
29
  <!-- Lunar Phase -->
30
30
  <g transform="translate(20,518)">
31
31
  <g transform="rotate($lunar_phase_rotate 20 10)">
@@ -14,7 +14,7 @@ Sign = Literal["Ari", "Tau", "Gem", "Can", "Leo", "Vir", "Lib", "Sco", "Sag", "C
14
14
 
15
15
 
16
16
  SignNumbers = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
17
- """Literal type for Zodiac Sign Numbers"""
17
+ """Literal type for Zodiac Sign Numbers, the signs are numbered in order starting from Aries (0) to Pisces (11)"""
18
18
 
19
19
 
20
20
  Houses = Literal["First_House", "Second_House", "Third_House", "Fourth_House", "Fifth_House", "Sixth_House", "Seventh_House", "Eighth_House", "Ninth_House", "Tenth_House", "Eleventh_House", "Twelfth_House"]
@@ -22,7 +22,7 @@ Houses = Literal["First_House", "Second_House", "Third_House", "Fourth_House", "
22
22
 
23
23
 
24
24
  HouseNumbers = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
25
- """Literal type for House Numbers"""
25
+ """Literal type for House Numbers, starting from the First House (1) to the Twelfth House (12)"""
26
26
 
27
27
 
28
28
  Planet = Literal["Sun", "Moon", "Mercury", "Venus", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", "Mean_Node", "True_Node", "Chiron"]
@@ -87,3 +87,15 @@ Y = APC houses
87
87
 
88
88
  Usually the standard is Placidus (P)
89
89
  """
90
+
91
+
92
+ PerspectiveType = Literal["Apparent Geocentric", "Heliocentric", "Topocentric", "True Geocentric"]
93
+ """
94
+ Literal type for perspective types.
95
+ - "Apparent Geocentric": Earth-centered, apparent positions.
96
+ - "Heliocentric": Sun-centered.
97
+ - "Topocentric": Observer's location on Earth's surface.
98
+ - "True Geocentric": Earth-centered, true positions.
99
+
100
+ Usually the standard is "Apparent Geocentric"
101
+ """
@@ -68,8 +68,9 @@ class AstrologicalSubjectModel(SubscriptableBaseModel):
68
68
  sidereal_mode: Union[SiderealMode, None]
69
69
  houses_system_identifier: HousesSystemIdentifier
70
70
  houses_system_name: str
71
- local_time: float
72
- utc_time: float
71
+ perspective_type: str
72
+ iso_formatted_local_datetime: str
73
+ iso_formatted_utc_datetime: str
73
74
  julian_day: float
74
75
 
75
76
  # Planets
@@ -108,6 +109,15 @@ class AstrologicalSubjectModel(SubscriptableBaseModel):
108
109
  # Lunar Phase
109
110
  lunar_phase: LunarPhaseModel
110
111
 
112
+ # Deprecated properties
113
+ utc_time: float
114
+ local_time: float
115
+
116
+ # Lists
117
+ # houses_list: list[KerykeionPointModel]
118
+ # planets_list: list[KerykeionPointModel]
119
+ # planets_degrees_ut: list[float]
120
+ # houses_degree_ut: list[float]
111
121
 
112
122
  if __name__ == "__main__":
113
123
  from kerykeion.utilities import setup_logging
@@ -354,3 +354,17 @@ def get_moon_phase_name_from_phase_int(phase: int) -> LunarPhaseName:
354
354
  raise KerykeionException(f"Error in moon name calculation! Phase: {phase}")
355
355
 
356
356
  return result
357
+
358
+
359
+ def check_and_adjust_polar_latitude(latitude: float, longitude: float) -> bool:
360
+ """
361
+ Utility function to check if the location is in the polar circle.
362
+ If it is, it sets the latitude to 66 or -66 degrees.
363
+ """
364
+ if latitude > 66.0:
365
+ latitude = 66.0
366
+ logging.info("Polar circle override for houses, using 66 degrees")
367
+
368
+ elif latitude < -66.0:
369
+ latitude = -66.0
370
+ logging.info("Polar circle override for houses, using -66 degrees")
@@ -1,10 +1,10 @@
1
1
  [tool.poetry]
2
2
  name = "kerykeion"
3
- version = "4.11.1"
3
+ version = "4.12.1"
4
4
  authors = ["Giacomo Battaglia <battaglia.giacomo@yahoo.it>"]
5
5
  description = "A python library for astrology."
6
6
  license = "AGPL-3.0"
7
- homepage = "https://github.com/g-battaglia/kerykeion"
7
+ homepage = "https://www.kerykeion.net/"
8
8
  repository = "https://github.com/g-battaglia/kerykeion"
9
9
  keywords = [
10
10
  "astrology",
File without changes