kerykeion 4.8.1__py3-none-any.whl → 4.12.3__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.

@@ -20,6 +20,7 @@ class ChartTemplateDictionary(TypedDict):
20
20
  viewbox: str
21
21
  stringTitle: str
22
22
  stringName: str
23
+ bottomLeft0: str
23
24
  bottomLeft1: str
24
25
  bottomLeft2: str
25
26
  bottomLeft3: str
@@ -1,68 +1,101 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
- This is part of Kerykeion (C) 2024 Giacomo Battaglia
3
+ This is part of Kerykeion (C) 2024 Giacomo Battaglia
4
4
  """
5
-
6
-
7
5
  from typing import Literal
8
6
 
9
- # Zodiac Types:
7
+
10
8
  ZodiacType = Literal["Tropic", "Sidereal"]
9
+ """Literal type for Zodiac Types"""
10
+
11
+
12
+ Sign = Literal["Ari", "Tau", "Gem", "Can", "Leo", "Vir", "Lib", "Sco", "Sag", "Cap", "Aqu", "Pis"]
13
+ """Literal type for Zodiac Signs"""
14
+
15
+
16
+ SignNumbers = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
17
+ """Literal type for Zodiac Sign Numbers, the signs are numbered in order starting from Aries (0) to Pisces (11)"""
18
+
19
+
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"]
21
+ """Literal type for Houses"""
22
+
23
+
24
+ HouseNumbers = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
25
+ """Literal type for House Numbers, starting from the First House (1) to the Twelfth House (12)"""
26
+
27
+
28
+ Planet = Literal["Sun", "Moon", "Mercury", "Venus", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", "Mean_Node", "True_Node", "Chiron"]
29
+ """Literal type for Planets"""
11
30
 
12
- # Sings:
13
- Sign = Literal[
14
- "Ari", "Tau", "Gem", "Can", "Leo", "Vir", "Lib", "Sco", "Sag", "Cap", "Aqu", "Pis"
15
- ]
16
-
17
- Houses = Literal[
18
- "First_House",
19
- "Second_House",
20
- "Third_House",
21
- "Fourth_House",
22
- "Fifth_House",
23
- "Sixth_House",
24
- "Seventh_House",
25
- "Eighth_House",
26
- "Ninth_House",
27
- "Tenth_House",
28
- "Eleventh_House",
29
- "Twelfth_House",
30
- ]
31
-
32
- Planet = Literal[
33
- "Sun",
34
- "Moon",
35
- "Mercury",
36
- "Venus",
37
- "Mars",
38
- "Jupiter",
39
- "Saturn",
40
- "Uranus",
41
- "Neptune",
42
- "Pluto",
43
- "Mean_Node",
44
- "True_Node",
45
- "Chiron",
46
- ]
47
31
 
48
32
  Element = Literal["Air", "Fire", "Earth", "Water"]
33
+ """Literal type for Elements"""
34
+
35
+
36
+ Quality = Literal["Cardinal", "Fixed", "Mutable"]
37
+ """Literal type for Qualities"""
49
38
 
50
- Quality = Literal[
51
- "Cardinal",
52
- "Fixed",
53
- "Mutable",
54
- ]
55
39
 
56
40
  ChartType = Literal["Natal", "ExternalNatal", "Synastry", "Transit"]
41
+ """Literal type for Chart Types"""
42
+
43
+
44
+ PointType = Literal["Planet", "House"]
45
+ """Literal type for Point Types"""
46
+
57
47
 
58
48
  LunarPhaseEmoji = Literal["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"]
59
- LunarPhaseName = Literal[
60
- "New Moon",
61
- "Waxing Crescent",
62
- "First Quarter",
63
- "Waxing Gibbous",
64
- "Full Moon",
65
- "Waning Gibbous",
66
- "Last Quarter",
67
- "Waning Crescent"
68
- ]
49
+ """Literal type for Lunar Phases Emoji"""
50
+
51
+
52
+ LunarPhaseName = Literal["New Moon", "Waxing Crescent", "First Quarter", "Waxing Gibbous", "Full Moon", "Waning Gibbous", "Last Quarter", "Waning Crescent"]
53
+ """Literal type for Lunar Phases Name"""
54
+
55
+
56
+ SiderealMode = Literal["FAGAN_BRADLEY", "LAHIRI", "DELUCE", "RAMAN", "USHASHASHI", "KRISHNAMURTI", "DJWHAL_KHUL", "YUKTESHWAR", "JN_BHASIN", "BABYL_KUGLER1", "BABYL_KUGLER2", "BABYL_KUGLER3", "BABYL_HUBER", "BABYL_ETPSC", "ALDEBARAN_15TAU", "HIPPARCHOS", "SASSANIAN", "J2000", "J1900", "B1950"]
57
+ """Literal type for Sidereal Modes, as known as Ayanamsa"""
58
+
59
+
60
+ HousesSystemIdentifier = Literal["A", "B", "C", "D", "F", "H", "I", "i", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"]
61
+ """
62
+ Literal type for Houses Systems:
63
+
64
+ A = equal
65
+ B = Alcabitius
66
+ C = Campanus
67
+ D = equal (MC)
68
+ F = Carter poli-equ.
69
+ H = horizon/azimut
70
+ I = Sunshine
71
+ i = Sunshine/alt.
72
+ K = Koch
73
+ L = Pullen SD
74
+ M = Morinus
75
+ N = equal/1=Aries
76
+ O = Porphyry
77
+ P = Placidus
78
+ Q = Pullen SR
79
+ R = Regiomontanus
80
+ S = Sripati
81
+ T = Polich/Page
82
+ U = Krusinski-Pisa-Goelzer
83
+ V = equal/Vehlow
84
+ W = equal/whole sign
85
+ X = axial rotation system/Meridian houses
86
+ Y = APC houses
87
+
88
+ Usually the standard is Placidus (P)
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
+ """
@@ -4,43 +4,15 @@
4
4
  """
5
5
 
6
6
 
7
- from typing import Literal, Union, Optional
7
+ from typing import Union, Optional
8
8
  from pydantic import BaseModel
9
9
 
10
- from kerykeion.kr_types import LunarPhaseEmoji, LunarPhaseName, Planet, Houses, Quality, Element, Sign, ZodiacType
11
-
12
-
13
- class LunarPhaseModel(BaseModel):
14
- degrees_between_s_m: Union[float, int]
15
- moon_phase: int
16
- sun_phase: int
17
- moon_emoji: LunarPhaseEmoji
18
- moon_phase_name: LunarPhaseName
19
-
20
- def __str__(self):
21
- return (
22
- super()
23
- .model_dump(
24
- exclude_none=True,
25
- exclude_unset=True,
26
- exclude_defaults=True,
27
- by_alias=False,
28
- )
29
- .__str__()
30
- )
31
-
32
- def __repr__(self):
33
- return (
34
- super()
35
- .model_dump(
36
- exclude_none=True,
37
- exclude_unset=True,
38
- exclude_defaults=True,
39
- by_alias=False,
40
- )
41
- .__str__()
42
- )
10
+ from kerykeion.kr_types import LunarPhaseEmoji, LunarPhaseName, Planet, Houses, Quality, Element, Sign, ZodiacType, SignNumbers, HouseNumbers, PointType, SiderealMode, HousesSystemIdentifier
43
11
 
12
+ class SubscriptableBaseModel(BaseModel):
13
+ """
14
+ Pydantic BaseModel with subscriptable support, so you can access the fields as if they were a dictionary.
15
+ """
44
16
  def __getitem__(self, key):
45
17
  return getattr(self, key)
46
18
 
@@ -53,8 +25,15 @@ class LunarPhaseModel(BaseModel):
53
25
  def get(self, key, default):
54
26
  return getattr(self, key, default)
55
27
 
28
+ class LunarPhaseModel(SubscriptableBaseModel):
29
+ degrees_between_s_m: Union[float, int]
30
+ moon_phase: int
31
+ sun_phase: int
32
+ moon_emoji: LunarPhaseEmoji
33
+ moon_phase_name: LunarPhaseName
34
+
56
35
 
57
- class KerykeionPointModel(BaseModel):
36
+ class KerykeionPointModel(SubscriptableBaseModel):
58
37
  """
59
38
  Kerykeion Point Model
60
39
  """
@@ -63,52 +42,16 @@ class KerykeionPointModel(BaseModel):
63
42
  quality: Quality
64
43
  element: Element
65
44
  sign: Sign
66
- sign_num: Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
45
+ sign_num: SignNumbers
67
46
  position: float
68
47
  abs_pos: float
69
48
  emoji: str
70
- point_type: Literal["Planet", "House"]
71
- house: Optional[Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]] = None
49
+ point_type: PointType
50
+ house: Optional[HouseNumbers] = None
72
51
  retrograde: Optional[bool] = None
73
52
 
74
- def __str__(self):
75
- return (
76
- super()
77
- .model_dump(
78
- exclude_none=True,
79
- exclude_unset=True,
80
- exclude_defaults=True,
81
- by_alias=False,
82
- )
83
- .__str__()
84
- )
85
-
86
- def __repr__(self):
87
- return (
88
- super()
89
- .model_dump(
90
- exclude_none=True,
91
- exclude_unset=True,
92
- exclude_defaults=True,
93
- by_alias=False,
94
- )
95
- .__str__()
96
- )
97
53
 
98
- def __getitem__(self, key):
99
- return getattr(self, key)
100
-
101
- def __setitem__(self, key, value):
102
- setattr(self, key, value)
103
-
104
- def __delitem__(self, key):
105
- delattr(self, key)
106
-
107
- def get(self, key, default):
108
- return getattr(self, key, default)
109
-
110
-
111
- class AstrologicalSubjectModel(BaseModel):
54
+ class AstrologicalSubjectModel(SubscriptableBaseModel):
112
55
  # Data
113
56
  name: str
114
57
  year: int
@@ -122,8 +65,12 @@ class AstrologicalSubjectModel(BaseModel):
122
65
  lat: float
123
66
  tz_str: str
124
67
  zodiac_type: ZodiacType
125
- local_time: float
126
- utc_time: float
68
+ sidereal_mode: Union[SiderealMode, None]
69
+ houses_system_identifier: HousesSystemIdentifier
70
+ houses_system_name: str
71
+ perspective_type: str
72
+ iso_formatted_local_datetime: str
73
+ iso_formatted_utc_datetime: str
127
74
  julian_day: float
128
75
 
129
76
  # Planets
@@ -137,6 +84,8 @@ class AstrologicalSubjectModel(BaseModel):
137
84
  uranus: KerykeionPointModel
138
85
  neptune: KerykeionPointModel
139
86
  pluto: KerykeionPointModel
87
+
88
+ # Optional Planets:
140
89
  chiron: Union[KerykeionPointModel, None]
141
90
 
142
91
  # Houses
@@ -160,6 +109,15 @@ class AstrologicalSubjectModel(BaseModel):
160
109
  # Lunar Phase
161
110
  lunar_phase: LunarPhaseModel
162
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]
163
121
 
164
122
  if __name__ == "__main__":
165
123
  from kerykeion.utilities import setup_logging
@@ -4,29 +4,12 @@
4
4
  """
5
5
 
6
6
 
7
- from pydantic import BaseModel, Field
7
+ from pydantic import Field
8
8
  from typing import List
9
+ from kerykeion.kr_types.kr_models import SubscriptableBaseModel
9
10
 
10
11
 
11
- class CustomBaseModel(BaseModel):
12
- """
13
- Extends the BaseModel class of Pydantic to add some useful methods.
14
- """
15
-
16
- def __init__(self, **data):
17
- super().__init__(**data)
18
-
19
- def __getitem__(self, item):
20
- return getattr(self, item)
21
-
22
- def __str__(self) -> str:
23
- return str(self.model_dump())
24
-
25
- def get(self, item, default=None):
26
- return getattr(self, item, default)
27
-
28
-
29
- class KerykeionSettingsCelestialPointModel(CustomBaseModel):
12
+ class KerykeionSettingsCelestialPointModel(SubscriptableBaseModel):
30
13
  """
31
14
  Defines the model for a celestial point data.
32
15
  """
@@ -41,7 +24,7 @@ class KerykeionSettingsCelestialPointModel(CustomBaseModel):
41
24
 
42
25
 
43
26
  # Chart Colors Settings
44
- class KerykeionSettingsChartColorsModel(CustomBaseModel):
27
+ class KerykeionSettingsChartColorsModel(SubscriptableBaseModel):
45
28
  """
46
29
  Defines the model for the chart colors.
47
30
  """
@@ -87,7 +70,7 @@ class KerykeionSettingsChartColorsModel(CustomBaseModel):
87
70
 
88
71
 
89
72
  # Aspect Settings
90
- class KerykeionSettingsAspectModel(CustomBaseModel):
73
+ class KerykeionSettingsAspectModel(SubscriptableBaseModel):
91
74
  """
92
75
  Defines the model for an aspect.
93
76
  """
@@ -103,7 +86,7 @@ class KerykeionSettingsAspectModel(CustomBaseModel):
103
86
 
104
87
 
105
88
  # Language Settings
106
- class KerykeionLanguageCelestialPointModel(CustomBaseModel):
89
+ class KerykeionLanguageCelestialPointModel(SubscriptableBaseModel):
107
90
  """
108
91
  This class is used to define the labels, show in the chart, for the celestial points.
109
92
  It is used to translate the celestial points in the language of the chart.
@@ -128,7 +111,7 @@ class KerykeionLanguageCelestialPointModel(CustomBaseModel):
128
111
  Ic: str = Field(title="Imum Coeli", description="The name of Imum Coeli in the chart, in the language")
129
112
 
130
113
 
131
- class KerykeionLanguageModel(CustomBaseModel):
114
+ class KerykeionLanguageModel(SubscriptableBaseModel):
132
115
  """
133
116
  This model is used to store the language settings for the chart,
134
117
  it's used to translate the celestial points and the other labels
@@ -157,17 +140,17 @@ class KerykeionLanguageModel(CustomBaseModel):
157
140
  celestial_points: KerykeionLanguageCelestialPointModel
158
141
 
159
142
 
160
- class KerykeionGeneralSettingsModel(CustomBaseModel):
143
+ class KerykeionGeneralSettingsModel(SubscriptableBaseModel):
161
144
  axes_orbit: int = Field(title="Axes Orbit", description="The orbit of the axes in the chart")
162
145
  planet_in_zodiac_extra_points: int = Field(title="Planet in Zodiac Extra Points", description="The extra points of the planet in the zodiac")
163
146
  language: str = Field(title="Language", description="The language of the chart")
164
147
 
165
- class KerykeionChartSettingsModel(CustomBaseModel):
148
+ class KerykeionChartSettingsModel(SubscriptableBaseModel):
166
149
  basic_chart_viewBox: str = Field(title="Basic Chart ViewBox", description="The viewbox of the basic chart")
167
150
  wide_chart_viewBox: str = Field(title="Wide Chart ViewBox", description="The viewbox of the wide chart")
168
151
 
169
152
  # Settings Model
170
- class KerykeionSettingsModel(CustomBaseModel):
153
+ class KerykeionSettingsModel(SubscriptableBaseModel):
171
154
  """
172
155
  This class is used to define the global settings for the Kerykeion.
173
156
  """
kerykeion/utilities.py CHANGED
@@ -1,47 +1,46 @@
1
1
  from kerykeion.kr_types import KerykeionPointModel, KerykeionException, KerykeionSettingsModel, AstrologicalSubjectModel
2
- from kerykeion.kr_types.kr_literals import LunarPhaseEmoji, LunarPhaseName
3
- from typing import Union, Literal
2
+ from kerykeion.kr_types.kr_literals import LunarPhaseEmoji, LunarPhaseName, PointType, Planet
3
+ from typing import Union
4
4
  import logging
5
5
  import math
6
6
 
7
7
 
8
8
 
9
- def get_number_from_name(name: str) -> int:
9
+ def get_number_from_name(name: Planet) -> int:
10
10
  """Utility function, gets planet id from the name."""
11
- name = name.lower()
12
11
 
13
- if name == "sun":
12
+ if name == "Sun":
14
13
  return 0
15
- elif name == "moon":
14
+ elif name == "Moon":
16
15
  return 1
17
- elif name == "mercury":
16
+ elif name == "Mercury":
18
17
  return 2
19
- elif name == "venus":
18
+ elif name == "Venus":
20
19
  return 3
21
- elif name == "mars":
20
+ elif name == "Mars":
22
21
  return 4
23
- elif name == "jupiter":
22
+ elif name == "Jupiter":
24
23
  return 5
25
- elif name == "saturn":
24
+ elif name == "Saturn":
26
25
  return 6
27
- elif name == "uranus":
26
+ elif name == "Uranus":
28
27
  return 7
29
- elif name == "neptune":
28
+ elif name == "Neptune":
30
29
  return 8
31
- elif name == "pluto":
30
+ elif name == "Pluto":
32
31
  return 9
33
- elif name == "mean_node":
32
+ elif name == "Mean_Node":
34
33
  return 10
35
- elif name == "true_node":
34
+ elif name == "True_Node":
36
35
  return 11
37
- elif name == "chiron":
36
+ elif name == "Chiron":
38
37
  return 15
39
38
  else:
40
- return int(name)
39
+ raise KerykeionException(f"Error in getting number from name! Name: {name}")
41
40
 
42
41
 
43
42
  def calculate_position(
44
- degree: Union[int, float], number_name: str, point_type: Literal["Planet", "House"]
43
+ degree: Union[int, float], number_name: str, point_type: PointType
45
44
  ) -> KerykeionPointModel:
46
45
  """Utility function to create a dictionary dividing the houses or the planets list."""
47
46
 
@@ -214,14 +213,14 @@ def setup_logging(level: str) -> None:
214
213
  Args:
215
214
  level: Log level as a string, options: debug, info, warning, error
216
215
  """
217
- logopt: dict[str, int] = {
216
+ logging_options: dict[str, int] = {
218
217
  "debug": logging.DEBUG,
219
218
  "info": logging.INFO,
220
219
  "warning": logging.WARNING,
221
220
  "error": logging.ERROR,
222
221
  }
223
222
  format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
224
- loglevel: int = logopt.get(level, logging.INFO)
223
+ loglevel: int = logging_options.get(level, logging.INFO)
225
224
  logging.basicConfig(format=format, level=loglevel)
226
225
 
227
226
  def check_if_point_between(
@@ -286,7 +285,7 @@ def get_planet_house(planet_position_degree: Union[int, float], houses_degree_ut
286
285
  elif check_if_point_between(houses_degree_ut_list[11], houses_degree_ut_list[0], planet_position_degree) == True:
287
286
  house = "Twelfth_House"
288
287
  else:
289
- raise ValueError("Error in house calculation, planet: ", planet_position_degree)
288
+ raise ValueError("Error in house calculation, planet: ", planet_position_degree, "houses: ", houses_degree_ut_list)
290
289
 
291
290
  return house
292
291
 
@@ -354,4 +353,18 @@ def get_moon_phase_name_from_phase_int(phase: int) -> LunarPhaseName:
354
353
  else:
355
354
  raise KerykeionException(f"Error in moon name calculation! Phase: {phase}")
356
355
 
357
- return result
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")