divineapi 1.2.0__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {divineapi-1.2.0 → divineapi-1.3.0}/PKG-INFO +18 -12
  2. {divineapi-1.2.0 → divineapi-1.3.0}/README.md +17 -11
  3. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/__init__.py +6 -4
  4. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/calculators.py +2 -2
  5. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/horoscope.py +27 -11
  6. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/pdf.py +23 -16
  7. divineapi-1.3.0/divineapi/western/_house_system.py +52 -0
  8. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/western/composite.py +2 -1
  9. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/western/natal.py +5 -4
  10. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/western/planet_returns.py +5 -3
  11. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/western/prenatal.py +2 -1
  12. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/western/progressions.py +16 -5
  13. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/western/synastry.py +2 -1
  14. divineapi-1.3.0/divineapi/western/transit.py +218 -0
  15. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi.egg-info/PKG-INFO +18 -12
  16. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi.egg-info/SOURCES.txt +1 -0
  17. {divineapi-1.2.0 → divineapi-1.3.0}/pyproject.toml +1 -1
  18. divineapi-1.2.0/divineapi/western/transit.py +0 -110
  19. {divineapi-1.2.0 → divineapi-1.3.0}/LICENSE +0 -0
  20. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/client.py +0 -0
  21. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/exceptions.py +0 -0
  22. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/indian/__init__.py +0 -0
  23. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/indian/festival.py +0 -0
  24. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/indian/kundli.py +0 -0
  25. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/indian/match_making.py +0 -0
  26. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/indian/panchang.py +0 -0
  27. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/lifestyle.py +0 -0
  28. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/numerology.py +0 -0
  29. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/py.typed +0 -0
  30. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi/western/__init__.py +0 -0
  31. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi.egg-info/dependency_links.txt +0 -0
  32. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi.egg-info/requires.txt +0 -0
  33. {divineapi-1.2.0 → divineapi-1.3.0}/divineapi.egg-info/top_level.txt +0 -0
  34. {divineapi-1.2.0 → divineapi-1.3.0}/setup.cfg +0 -0
  35. {divineapi-1.2.0 → divineapi-1.3.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: divineapi
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: Official Python SDK for the Divine API - Astrology, Numerology, Tarot & more
5
5
  Author-email: Divine API <support@divineapi.com>
6
6
  License: MIT
@@ -51,9 +51,9 @@ from divineapi import DivineApi
51
51
 
52
52
  client = DivineApi(api_key="your-api-key", auth_token="your-bearer-token")
53
53
 
54
- # Daily Horoscope
54
+ # Daily Horoscope (h_day = today, tomorrow, or yesterday)
55
55
  result = client.horoscope.daily(
56
- sign="aries", day=10, month=3, year=2024, tzone=5.5
56
+ sign="aries", h_day="today", tzone=5.5
57
57
  )
58
58
  print(result)
59
59
  ```
@@ -64,10 +64,11 @@ print(result)
64
64
 
65
65
  ```python
66
66
  # Daily / Weekly / Monthly / Yearly Horoscope
67
- client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
68
- client.horoscope.weekly(sign="leo", week="thisweek", tzone=5.5)
69
- client.horoscope.monthly(sign="cancer", month=3, tzone=5.5)
70
- client.horoscope.yearly(sign="virgo", year=2024, tzone=5.5)
67
+ # daily h_day = today / tomorrow / yesterday; weekly/monthly/yearly = current / prev / next
68
+ client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
69
+ client.horoscope.weekly(sign="leo", week="current", tzone=5.5)
70
+ client.horoscope.monthly(sign="cancer", month="current", tzone=5.5)
71
+ client.horoscope.yearly(sign="virgo", year="current", tzone=5.5)
71
72
 
72
73
  # Chinese & Numerology Horoscope
73
74
  client.horoscope.chinese(sign="rat", h_day="today", tzone=5.5)
@@ -164,8 +165,9 @@ client.indian.festival.chaitra_festivals(
164
165
  client.indian.festival.english_calendar(
165
166
  year=2024, month=3, place="Delhi", lat=28.6, lon=77.2, tzone=5.5
166
167
  )
168
+ # festival is a lowercase snake_case slug from the Divine festival list
167
169
  client.indian.festival.find_festival(
168
- festival="diwali", year=2024,
170
+ festival="maha_shivratri", year=2024,
169
171
  place="Delhi", lat=28.6, lon=77.2, tzone=5.5
170
172
  )
171
173
  client.indian.festival.malayalam_festivals(
@@ -193,7 +195,7 @@ client.western.natal.house_cusps(**birth_w)
193
195
  client.western.natal.aspect_table(**birth_w)
194
196
  client.western.natal.natal_wheel_chart(**birth_w)
195
197
  client.western.natal.natal_insights(**birth_w)
196
- client.western.natal.dominants(method="traditional", **birth_w)
198
+ client.western.natal.dominants(method="TRADITIONAL", **birth_w)
197
199
  ```
198
200
 
199
201
  ### Western Astrology - Synastry
@@ -252,7 +254,7 @@ client.lifestyle.astro_chic_picks(sign="virgo", h_day="today", tzone=5.5)
252
254
  ### Calculators
253
255
 
254
256
  ```python
255
- client.calculators.flames(full_name="John", partner_name="Jane")
257
+ client.calculators.flames(your_name="John", partner_name="Jane")
256
258
  client.calculators.love_calculator(
257
259
  your_name="John", partner_name="Jane",
258
260
  your_gender="male", partner_gender="female",
@@ -262,11 +264,15 @@ client.calculators.love_calculator(
262
264
  ### PDF Reports
263
265
 
264
266
  ```python
267
+ # The six branding fields (company_url, logo_url, footer_text, company_name,
268
+ # company_email, company_bio) are REQUIRED by the PDF backend.
265
269
  client.pdf.kundali_sampoorna(
266
270
  full_name="John", day=1, month=1, year=1990,
267
271
  hour=10, min=30, sec=0, gender="male",
268
272
  place="Mumbai", lat=19.07, lon=72.87, tzone=5.5,
269
273
  company_name="AstroCo", company_url="https://example.com",
274
+ company_email="hello@example.com", company_bio="We do astrology.",
275
+ logo_url="https://example.com/logo.png", footer_text="(c) AstroCo",
270
276
  )
271
277
  ```
272
278
 
@@ -278,7 +284,7 @@ from divineapi import DivineApi, AuthenticationError, ValidationError, RateLimit
278
284
  client = DivineApi(api_key="...", auth_token="...")
279
285
 
280
286
  try:
281
- result = client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
287
+ result = client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
282
288
  except AuthenticationError as e:
283
289
  print(f"Auth failed: {e}")
284
290
  except ValidationError as e:
@@ -291,7 +297,7 @@ except RateLimitError as e:
291
297
 
292
298
  ```python
293
299
  with DivineApi(api_key="...", auth_token="...") as client:
294
- result = client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
300
+ result = client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
295
301
  ```
296
302
 
297
303
  ## Configuration
@@ -23,9 +23,9 @@ from divineapi import DivineApi
23
23
 
24
24
  client = DivineApi(api_key="your-api-key", auth_token="your-bearer-token")
25
25
 
26
- # Daily Horoscope
26
+ # Daily Horoscope (h_day = today, tomorrow, or yesterday)
27
27
  result = client.horoscope.daily(
28
- sign="aries", day=10, month=3, year=2024, tzone=5.5
28
+ sign="aries", h_day="today", tzone=5.5
29
29
  )
30
30
  print(result)
31
31
  ```
@@ -36,10 +36,11 @@ print(result)
36
36
 
37
37
  ```python
38
38
  # Daily / Weekly / Monthly / Yearly Horoscope
39
- client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
40
- client.horoscope.weekly(sign="leo", week="thisweek", tzone=5.5)
41
- client.horoscope.monthly(sign="cancer", month=3, tzone=5.5)
42
- client.horoscope.yearly(sign="virgo", year=2024, tzone=5.5)
39
+ # daily h_day = today / tomorrow / yesterday; weekly/monthly/yearly = current / prev / next
40
+ client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
41
+ client.horoscope.weekly(sign="leo", week="current", tzone=5.5)
42
+ client.horoscope.monthly(sign="cancer", month="current", tzone=5.5)
43
+ client.horoscope.yearly(sign="virgo", year="current", tzone=5.5)
43
44
 
44
45
  # Chinese & Numerology Horoscope
45
46
  client.horoscope.chinese(sign="rat", h_day="today", tzone=5.5)
@@ -136,8 +137,9 @@ client.indian.festival.chaitra_festivals(
136
137
  client.indian.festival.english_calendar(
137
138
  year=2024, month=3, place="Delhi", lat=28.6, lon=77.2, tzone=5.5
138
139
  )
140
+ # festival is a lowercase snake_case slug from the Divine festival list
139
141
  client.indian.festival.find_festival(
140
- festival="diwali", year=2024,
142
+ festival="maha_shivratri", year=2024,
141
143
  place="Delhi", lat=28.6, lon=77.2, tzone=5.5
142
144
  )
143
145
  client.indian.festival.malayalam_festivals(
@@ -165,7 +167,7 @@ client.western.natal.house_cusps(**birth_w)
165
167
  client.western.natal.aspect_table(**birth_w)
166
168
  client.western.natal.natal_wheel_chart(**birth_w)
167
169
  client.western.natal.natal_insights(**birth_w)
168
- client.western.natal.dominants(method="traditional", **birth_w)
170
+ client.western.natal.dominants(method="TRADITIONAL", **birth_w)
169
171
  ```
170
172
 
171
173
  ### Western Astrology - Synastry
@@ -224,7 +226,7 @@ client.lifestyle.astro_chic_picks(sign="virgo", h_day="today", tzone=5.5)
224
226
  ### Calculators
225
227
 
226
228
  ```python
227
- client.calculators.flames(full_name="John", partner_name="Jane")
229
+ client.calculators.flames(your_name="John", partner_name="Jane")
228
230
  client.calculators.love_calculator(
229
231
  your_name="John", partner_name="Jane",
230
232
  your_gender="male", partner_gender="female",
@@ -234,11 +236,15 @@ client.calculators.love_calculator(
234
236
  ### PDF Reports
235
237
 
236
238
  ```python
239
+ # The six branding fields (company_url, logo_url, footer_text, company_name,
240
+ # company_email, company_bio) are REQUIRED by the PDF backend.
237
241
  client.pdf.kundali_sampoorna(
238
242
  full_name="John", day=1, month=1, year=1990,
239
243
  hour=10, min=30, sec=0, gender="male",
240
244
  place="Mumbai", lat=19.07, lon=72.87, tzone=5.5,
241
245
  company_name="AstroCo", company_url="https://example.com",
246
+ company_email="hello@example.com", company_bio="We do astrology.",
247
+ logo_url="https://example.com/logo.png", footer_text="(c) AstroCo",
242
248
  )
243
249
  ```
244
250
 
@@ -250,7 +256,7 @@ from divineapi import DivineApi, AuthenticationError, ValidationError, RateLimit
250
256
  client = DivineApi(api_key="...", auth_token="...")
251
257
 
252
258
  try:
253
- result = client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
259
+ result = client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
254
260
  except AuthenticationError as e:
255
261
  print(f"Auth failed: {e}")
256
262
  except ValidationError as e:
@@ -263,7 +269,7 @@ except RateLimitError as e:
263
269
 
264
270
  ```python
265
271
  with DivineApi(api_key="...", auth_token="...") as client:
266
- result = client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
272
+ result = client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
267
273
  ```
268
274
 
269
275
  ## Configuration
@@ -5,7 +5,7 @@ Usage::
5
5
  from divineapi import DivineApi
6
6
 
7
7
  client = DivineApi(api_key="your-api-key", auth_token="your-bearer-token")
8
- result = client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
8
+ result = client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
9
9
  print(result)
10
10
  """
11
11
 
@@ -29,7 +29,7 @@ from .numerology import NumerologyApi
29
29
  from .pdf import PdfReportApi
30
30
  from .western import WesternApi
31
31
 
32
- __version__ = "1.2.0"
32
+ __version__ = "1.3.0"
33
33
 
34
34
  __all__ = [
35
35
  "DivineApi",
@@ -57,7 +57,7 @@ class DivineApi:
57
57
  client = DivineApi(api_key="...", auth_token="...")
58
58
 
59
59
  # Horoscope & Tarot
60
- client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
60
+ client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
61
61
 
62
62
  # Indian Panchang
63
63
  client.indian.panchang.find_panchang(
@@ -100,7 +100,9 @@ class DivineApi:
100
100
  full_name="John", day=1, month=1, year=1990,
101
101
  hour=10, min=30, sec=0, gender="male",
102
102
  place="Mumbai", lat=19.07, lon=72.87, tzone=5.5,
103
- company_name="MyCompany",
103
+ company_name="MyCompany", company_url="https://example.com",
104
+ company_email="hello@example.com", company_bio="We do astrology.",
105
+ logo_url="https://example.com/logo.png", footer_text="(c) MyCompany",
104
106
  )
105
107
  """
106
108
 
@@ -13,10 +13,10 @@ class CalculatorApi:
13
13
  def __init__(self, client: BaseClient) -> None:
14
14
  self._c = client
15
15
 
16
- def flames(self, full_name: str, partner_name: str) -> Dict[str, Any]:
16
+ def flames(self, your_name: str, partner_name: str) -> Dict[str, Any]:
17
17
  """FLAMES Calculator."""
18
18
  return self._c.post(HOST, "/calculator/v1/flames-calculator", {
19
- "full_name": full_name, "partner_name": partner_name,
19
+ "your_name": your_name, "partner_name": partner_name,
20
20
  })
21
21
 
22
22
  def love_calculator(
@@ -20,16 +20,21 @@ class HoroscopeApi:
20
20
  def daily(
21
21
  self,
22
22
  sign: str,
23
- day: int,
24
- month: int,
25
- year: int,
23
+ h_day: str,
26
24
  tzone: float,
27
25
  lan: str = "en",
26
+ day: Optional[int] = None,
27
+ month: Optional[int] = None,
28
+ year: Optional[int] = None,
28
29
  ) -> Dict[str, Any]:
29
- """Daily Horoscope."""
30
+ """Daily Horoscope.
31
+
32
+ The reading is selected with ``h_day`` ('today', 'tomorrow', or
33
+ 'yesterday'). ``day``/``month``/``year`` are deprecated: the API
34
+ ignores them and they are accepted only for backward compatibility.
35
+ """
30
36
  return self._c.post(HOST, "/api/v5/daily-horoscope", {
31
- "sign": sign, "day": day, "month": month, "year": year,
32
- "tzone": tzone, "lan": lan,
37
+ "sign": sign, "h_day": h_day, "tzone": tzone, "lan": lan,
33
38
  })
34
39
 
35
40
  def weekly(
@@ -39,7 +44,10 @@ class HoroscopeApi:
39
44
  tzone: float,
40
45
  lan: str = "en",
41
46
  ) -> Dict[str, Any]:
42
- """Weekly Horoscope."""
47
+ """Weekly Horoscope.
48
+
49
+ ``week`` is a selector: 'current', 'prev', or 'next' (not a date).
50
+ """
43
51
  return self._c.post(HOST, "/api/v5/weekly-horoscope", {
44
52
  "sign": sign, "week": week, "tzone": tzone, "lan": lan,
45
53
  })
@@ -47,11 +55,15 @@ class HoroscopeApi:
47
55
  def monthly(
48
56
  self,
49
57
  sign: str,
50
- month: int,
58
+ month: str,
51
59
  tzone: float,
52
60
  lan: str = "en",
53
61
  ) -> Dict[str, Any]:
54
- """Monthly Horoscope."""
62
+ """Monthly Horoscope.
63
+
64
+ ``month`` is a selector: 'current', 'prev', or 'next' (not a calendar
65
+ month number).
66
+ """
55
67
  return self._c.post(HOST, "/api/v5/monthly-horoscope", {
56
68
  "sign": sign, "month": month, "tzone": tzone, "lan": lan,
57
69
  })
@@ -59,11 +71,15 @@ class HoroscopeApi:
59
71
  def yearly(
60
72
  self,
61
73
  sign: str,
62
- year: int,
74
+ year: str,
63
75
  tzone: float,
64
76
  lan: str = "en",
65
77
  ) -> Dict[str, Any]:
66
- """Yearly Horoscope."""
78
+ """Yearly Horoscope.
79
+
80
+ ``year`` is a selector: 'current', 'prev', or 'next' (not a calendar
81
+ year number).
82
+ """
67
83
  return self._c.post(HOST, "/api/v5/yearly-horoscope", {
68
84
  "sign": sign, "year": year, "tzone": tzone, "lan": lan,
69
85
  })
@@ -22,23 +22,26 @@ class PdfReportApi:
22
22
  full_name: str, day: int, month: int, year: int,
23
23
  hour: int, min: int, sec: int, gender: str,
24
24
  place: str, lat: float, lon: float, tzone: float,
25
- lan: str = "en",
26
- company_name: str = "", company_url: str = "",
27
- company_email: str = "", company_mobile: str = "",
28
- company_bio: str = "", logo_url: str = "",
29
- footer_text: str = "",
25
+ company_name: str, company_url: str, company_email: str,
26
+ company_bio: str, logo_url: str, footer_text: str,
27
+ lan: str = "en", company_mobile: str = "",
30
28
  **extra: Any,
31
29
  ) -> Dict[str, Any]:
30
+ # The six branding fields are REQUIRED by the PDF backend (it rejects
31
+ # requests without them). company_mobile is optional and sent only when
32
+ # provided.
32
33
  d: Dict[str, Any] = {
33
34
  "full_name": full_name, "day": day, "month": month, "year": year,
34
35
  "hour": hour, "min": min, "sec": sec, "gender": gender,
35
36
  "place": place, "lat": lat, "lon": lon, "tzone": tzone,
36
37
  "lan": lan,
37
38
  "company_name": company_name, "company_url": company_url,
38
- "company_email": company_email, "company_mobile": company_mobile,
39
+ "company_email": company_email,
39
40
  "company_bio": company_bio, "logo_url": logo_url,
40
41
  "footer_text": footer_text,
41
42
  }
43
+ if company_mobile:
44
+ d["company_mobile"] = company_mobile
42
45
  d.update(extra)
43
46
  return d
44
47
 
@@ -50,13 +53,12 @@ class PdfReportApi:
50
53
  p2_full_name: str, p2_day: int, p2_month: int, p2_year: int,
51
54
  p2_hour: int, p2_min: int, p2_sec: int, p2_gender: str,
52
55
  p2_place: str, p2_lat: float, p2_lon: float, p2_tzone: float,
53
- lan: str = "en",
54
- company_name: str = "", company_url: str = "",
55
- company_email: str = "", company_mobile: str = "",
56
- company_bio: str = "", logo_url: str = "",
57
- footer_text: str = "",
56
+ company_name: str, company_url: str, company_email: str,
57
+ company_bio: str, logo_url: str, footer_text: str,
58
+ lan: str = "en", company_mobile: str = "",
58
59
  **extra: Any,
59
60
  ) -> Dict[str, Any]:
61
+ # The six branding fields are REQUIRED by the PDF backend.
60
62
  d: Dict[str, Any] = {
61
63
  "p1_full_name": p1_full_name, "p1_day": p1_day, "p1_month": p1_month,
62
64
  "p1_year": p1_year, "p1_hour": p1_hour, "p1_min": p1_min,
@@ -68,10 +70,12 @@ class PdfReportApi:
68
70
  "p2_lat": p2_lat, "p2_lon": p2_lon, "p2_tzone": p2_tzone,
69
71
  "lan": lan,
70
72
  "company_name": company_name, "company_url": company_url,
71
- "company_email": company_email, "company_mobile": company_mobile,
73
+ "company_email": company_email,
72
74
  "company_bio": company_bio, "logo_url": logo_url,
73
75
  "footer_text": footer_text,
74
76
  }
77
+ if company_mobile:
78
+ d["company_mobile"] = company_mobile
75
79
  d.update(extra)
76
80
  return d
77
81
 
@@ -133,11 +137,14 @@ class PdfReportApi:
133
137
  # Astrology / Numerology reports with report_code
134
138
  # ------------------------------------------------------------------ #
135
139
 
136
- def natal_report(self, report_code: str, theme: str = "", **kw: Any) -> Dict[str, Any]:
137
- """Natal Report PDF."""
140
+ def natal_report(self, report_code: str, theme: str, **kw: Any) -> Dict[str, Any]:
141
+ """Natal Report PDF.
142
+
143
+ Both ``report_code`` (e.g. 'CAREER-REPORT') and ``theme`` (e.g. '001')
144
+ are required by the API, along with the six company branding fields.
145
+ """
138
146
  kw["report_code"] = report_code
139
- if theme:
140
- kw["theme"] = theme
147
+ kw["theme"] = theme
141
148
  return self._post_birth("/astrology/v2/report", **kw)
142
149
 
143
150
  def natal_couple_report(self, report_code: str, **kw: Any) -> Dict[str, Any]:
@@ -0,0 +1,52 @@
1
+ """House-system name resolution for the Western API.
2
+
3
+ The live Western API accepts ONLY single-letter Swiss Ephemeris house-system
4
+ codes. Word values like ``placidus`` are rejected on astroapi-4 and silently
5
+ ignored on astroapi-8, so every payload must send the letter code. This mirrors
6
+ the mapping used by the Divine Western MCP server.
7
+ """
8
+
9
+ from typing import Optional
10
+
11
+ # Friendly house-system names mapped to the single-letter API codes.
12
+ HOUSE_SYSTEM_MAP = {
13
+ "placidus": "P",
14
+ "koch": "K",
15
+ "porphyry": "O",
16
+ "regiomontanus": "R",
17
+ "campanus": "C",
18
+ "equal": "E",
19
+ "whole-sign": "W",
20
+ "whole_sign": "W",
21
+ "wholesign": "W",
22
+ "morinus": "M",
23
+ "alcabitius": "B",
24
+ }
25
+ VALID_HOUSE_SYSTEM_LETTERS = set(HOUSE_SYSTEM_MAP.values())
26
+ HOUSE_SYSTEM_FRIENDLY_NAMES = (
27
+ "placidus, koch, porphyry, regiomontanus, campanus, equal, "
28
+ "whole-sign, morinus, alcabitius"
29
+ )
30
+
31
+
32
+ def resolve_house_system(value: Optional[str]) -> str:
33
+ """Map a friendly house-system name to its single-letter API code.
34
+
35
+ Accepts friendly names case-insensitively (e.g. ``placidus``, ``Whole-Sign``)
36
+ and already-valid single letters (passed through unchanged, upper-cased).
37
+ An empty value defaults to ``P`` (Placidus). Raises ``ValueError`` for
38
+ anything else.
39
+ """
40
+ hs = (value or "").strip()
41
+ if not hs:
42
+ return "P"
43
+ if hs.upper() in VALID_HOUSE_SYSTEM_LETTERS:
44
+ return hs.upper()
45
+ mapped = HOUSE_SYSTEM_MAP.get(hs.lower())
46
+ if mapped:
47
+ return mapped
48
+ raise ValueError(
49
+ f"Invalid house_system '{value}'. Must be one of: "
50
+ f"{HOUSE_SYSTEM_FRIENDLY_NAMES} (or a single-letter code: "
51
+ f"{', '.join(sorted(VALID_HOUSE_SYSTEM_LETTERS))})"
52
+ )
@@ -3,6 +3,7 @@
3
3
  from typing import Any, Dict
4
4
 
5
5
  from ..client import BaseClient
6
+ from ._house_system import resolve_house_system
6
7
 
7
8
  HOST = "astroapi-8"
8
9
 
@@ -33,7 +34,7 @@ class CompositeApi:
33
34
  "p2_year": p2_year, "p2_hour": p2_hour, "p2_min": p2_min,
34
35
  "p2_sec": p2_sec, "p2_gender": p2_gender, "p2_place": p2_place,
35
36
  "p2_lat": p2_lat, "p2_lon": p2_lon, "p2_tzone": p2_tzone,
36
- "lan": lan, "house_system": house_system,
37
+ "lan": lan, "house_system": resolve_house_system(house_system),
37
38
  }
38
39
  d.update(extra)
39
40
  return d
@@ -1,8 +1,9 @@
1
1
  """Western API - Natal endpoints (astroapi-4 and astroapi-8)."""
2
2
 
3
- from typing import Any, Dict, List, Optional
3
+ from typing import Any, Dict
4
4
 
5
5
  from ..client import BaseClient
6
+ from ._house_system import resolve_house_system
6
7
 
7
8
 
8
9
  class NatalApi:
@@ -27,7 +28,7 @@ class NatalApi:
27
28
  "full_name": full_name, "day": day, "month": month, "year": year,
28
29
  "hour": hour, "min": min, "sec": sec, "gender": gender,
29
30
  "place": place, "lat": lat, "lon": lon, "tzone": tzone,
30
- "lan": lan, "house_system": house_system,
31
+ "lan": lan, "house_system": resolve_house_system(house_system),
31
32
  }
32
33
  d.update(extra)
33
34
  return d
@@ -44,11 +45,11 @@ class NatalApi:
44
45
 
45
46
  def planetary_positions(self, **kw: Any) -> Dict[str, Any]:
46
47
  """Natal Planetary Positions."""
47
- return self._post4("/western-api/v2/planetary-positions", **kw)
48
+ return self._post4("/western-api/v1/planetary-positions", **kw)
48
49
 
49
50
  def house_cusps(self, **kw: Any) -> Dict[str, Any]:
50
51
  """Natal House Cusps."""
51
- return self._post4("/western-api/v2/house-cusps", **kw)
52
+ return self._post4("/western-api/v1/house-cusps", **kw)
52
53
 
53
54
  def aspect_table(self, **kw: Any) -> Dict[str, Any]:
54
55
  """Natal Aspect Table."""
@@ -3,6 +3,7 @@
3
3
  from typing import Any, Dict
4
4
 
5
5
  from ..client import BaseClient
6
+ from ._house_system import resolve_house_system
6
7
 
7
8
  HOST = "astroapi-8"
8
9
 
@@ -25,7 +26,7 @@ class PlanetReturnsApi:
25
26
  "full_name": full_name, "day": day, "month": month, "year": year,
26
27
  "hour": hour, "min": min, "sec": sec, "gender": gender,
27
28
  "place": place, "lat": lat, "lon": lon, "tzone": tzone,
28
- "lan": lan, "house_system": house_system,
29
+ "lan": lan, "house_system": resolve_house_system(house_system),
29
30
  }
30
31
  d.update(extra)
31
32
  return d
@@ -46,14 +47,15 @@ class PlanetReturnsApi:
46
47
  return self._c.post(HOST, "/western-api/v1/planet-returns-list", self._birth(**kw))
47
48
 
48
49
  def planet_return_details(
49
- self, planet: str, return_key: str,
50
+ self, planet: str, return_key: str, return_year: int,
50
51
  return_lat: float, return_lon: float,
51
52
  return_tzone: float, return_place: str,
52
53
  **kw: Any,
53
54
  ) -> Dict[str, Any]:
54
- """Planet Return Details."""
55
+ """Planet Return Details (``return_key`` comes from ``planet_return_list``)."""
55
56
  kw["planet"] = planet
56
57
  kw["return_key"] = return_key
58
+ kw["return_year"] = return_year
57
59
  kw["return_lat"] = return_lat
58
60
  kw["return_lon"] = return_lon
59
61
  kw["return_tzone"] = return_tzone
@@ -3,6 +3,7 @@
3
3
  from typing import Any, Dict
4
4
 
5
5
  from ..client import BaseClient
6
+ from ._house_system import resolve_house_system
6
7
 
7
8
  HOST = "astroapi-8"
8
9
 
@@ -25,7 +26,7 @@ class PrenatalApi:
25
26
  "full_name": full_name, "day": day, "month": month, "year": year,
26
27
  "hour": hour, "min": min, "sec": sec, "gender": gender,
27
28
  "place": place, "lat": lat, "lon": lon, "tzone": tzone,
28
- "lan": lan, "house_system": house_system,
29
+ "lan": lan, "house_system": resolve_house_system(house_system),
29
30
  }
30
31
  d.update(extra)
31
32
  return d
@@ -1,8 +1,9 @@
1
1
  """Western API - Progressions endpoints (astroapi-8)."""
2
2
 
3
- from typing import Any, Dict
3
+ from typing import Any, Dict, Optional
4
4
 
5
5
  from ..client import BaseClient
6
+ from ._house_system import resolve_house_system
6
7
 
7
8
  HOST = "astroapi-8"
8
9
 
@@ -25,7 +26,7 @@ class ProgressionsApi:
25
26
  "full_name": full_name, "day": day, "month": month, "year": year,
26
27
  "hour": hour, "min": min, "sec": sec, "gender": gender,
27
28
  "place": place, "lat": lat, "lon": lon, "tzone": tzone,
28
- "lan": lan, "house_system": house_system,
29
+ "lan": lan, "house_system": resolve_house_system(house_system),
29
30
  }
30
31
  d.update(extra)
31
32
  return d
@@ -48,15 +49,25 @@ class ProgressionsApi:
48
49
  return self._c.post(HOST, "/western-api/v1/planetary-arc-directions", self._birth(**kw))
49
50
 
50
51
  def secondary_progressions(
51
- self, planet: str,
52
+ self,
52
53
  progressed_day: int, progressed_month: int, progressed_year: int,
54
+ progressed_hour: int, progressed_min: int, progressed_sec: int,
53
55
  progressed_type: str,
56
+ planet: Optional[str] = None,
54
57
  **kw: Any,
55
58
  ) -> Dict[str, Any]:
56
- """Secondary Progressions."""
57
- kw["planet"] = planet
59
+ """Secondary Progressions.
60
+
61
+ ``progressed_day/month/year/hour/min/sec`` and ``progressed_type`` are
62
+ required by the API; ``planet`` is optional.
63
+ """
58
64
  kw["progressed_day"] = progressed_day
59
65
  kw["progressed_month"] = progressed_month
60
66
  kw["progressed_year"] = progressed_year
67
+ kw["progressed_hour"] = progressed_hour
68
+ kw["progressed_min"] = progressed_min
69
+ kw["progressed_sec"] = progressed_sec
61
70
  kw["progressed_type"] = progressed_type
71
+ if planet is not None:
72
+ kw["planet"] = planet
62
73
  return self._c.post(HOST, "/western-api/v1/secondary-progressions", self._birth(**kw))
@@ -3,6 +3,7 @@
3
3
  from typing import Any, Dict
4
4
 
5
5
  from ..client import BaseClient
6
+ from ._house_system import resolve_house_system
6
7
 
7
8
  HOST = "astroapi-4"
8
9
  HOST8 = "astroapi-8"
@@ -38,7 +39,7 @@ class SynastryApi:
38
39
  "p2_year": p2_year, "p2_hour": p2_hour, "p2_min": p2_min,
39
40
  "p2_sec": p2_sec, "p2_gender": p2_gender, "p2_place": p2_place,
40
41
  "p2_lat": p2_lat, "p2_lon": p2_lon, "p2_tzone": p2_tzone,
41
- "lan": lan, "house_system": house_system,
42
+ "lan": lan, "house_system": resolve_house_system(house_system),
42
43
  }
43
44
  d.update(extra)
44
45
  return d
@@ -0,0 +1,218 @@
1
+ """Western API - Transit endpoints (astroapi-4 and astroapi-8)."""
2
+
3
+ from typing import Any, Dict
4
+
5
+ from ..client import BaseClient
6
+ from ._house_system import resolve_house_system
7
+
8
+
9
+ class TransitApi:
10
+ """Transit endpoints for Western astrology."""
11
+
12
+ def __init__(self, client: BaseClient) -> None:
13
+ self._c = client
14
+
15
+ # ------------------------------------------------------------------ #
16
+ # Payload helpers
17
+ # ------------------------------------------------------------------ #
18
+
19
+ @staticmethod
20
+ def _birth(
21
+ full_name: str, day: int, month: int, year: int,
22
+ hour: int, min: int, sec: int, gender: str,
23
+ place: str, lat: float, lon: float, tzone: float,
24
+ lan: str = "en", house_system: str = "placidus",
25
+ **extra: Any,
26
+ ) -> Dict[str, Any]:
27
+ d: Dict[str, Any] = {
28
+ "full_name": full_name, "day": day, "month": month, "year": year,
29
+ "hour": hour, "min": min, "sec": sec, "gender": gender,
30
+ "place": place, "lat": lat, "lon": lon, "tzone": tzone,
31
+ "lan": lan, "house_system": resolve_house_system(house_system),
32
+ }
33
+ d.update(extra)
34
+ return d
35
+
36
+ @staticmethod
37
+ def _transit_dt(
38
+ transit_day: int, transit_month: int, transit_year: int,
39
+ transit_hour: int = 0, transit_min: int = 0, transit_sec: int = 0,
40
+ ) -> Dict[str, Any]:
41
+ return {
42
+ "transit_day": transit_day, "transit_month": transit_month,
43
+ "transit_year": transit_year, "transit_hour": transit_hour,
44
+ "transit_min": transit_min, "transit_sec": transit_sec,
45
+ }
46
+
47
+ @staticmethod
48
+ def _transit_loc(
49
+ transit_lat: float, transit_lon: float,
50
+ transit_tzone: float, transit_place: str,
51
+ ) -> Dict[str, Any]:
52
+ return {
53
+ "transit_lat": transit_lat, "transit_lon": transit_lon,
54
+ "transit_tzone": transit_tzone, "transit_place": transit_place,
55
+ }
56
+
57
+ def _post4(self, path: str, **kw: Any) -> Dict[str, Any]:
58
+ return self._c.post("astroapi-4", path, self._birth(**kw))
59
+
60
+ def _post8(self, path: str, **kw: Any) -> Dict[str, Any]:
61
+ return self._c.post("astroapi-8", path, self._birth(**kw))
62
+
63
+ # ------------------------------------------------------------------ #
64
+ # astroapi-4 transit endpoints
65
+ # ------------------------------------------------------------------ #
66
+
67
+ def basic(
68
+ self,
69
+ transit_day: int, transit_month: int, transit_year: int,
70
+ transit_hour: int = 0, transit_min: int = 0, transit_sec: int = 0,
71
+ **kw: Any,
72
+ ) -> Dict[str, Any]:
73
+ """Transit Basic. Requires the transit date; time defaults to 00:00:00."""
74
+ payload = self._birth(**kw)
75
+ payload.update(self._transit_dt(
76
+ transit_day, transit_month, transit_year,
77
+ transit_hour, transit_min, transit_sec,
78
+ ))
79
+ return self._c.post("astroapi-4", "/western-api/v1/transit/basic", payload)
80
+
81
+ def daily(self, **kw: Any) -> Dict[str, Any]:
82
+ """Transit Daily."""
83
+ return self._post4("/western-api/v1/transit/daily", **kw)
84
+
85
+ def weekly(self, transit_planet: str, **kw: Any) -> Dict[str, Any]:
86
+ """Transit Weekly. Requires the transiting planet (e.g. 'moon')."""
87
+ kw["transit_planet"] = transit_planet
88
+ return self._post4("/western-api/v1/transit/weekly", **kw)
89
+
90
+ def house(
91
+ self,
92
+ transit_day: int, transit_month: int, transit_year: int,
93
+ transit_lat: float, transit_lon: float,
94
+ transit_tzone: float, transit_place: str,
95
+ transit_hour: int = 0, transit_min: int = 0, transit_sec: int = 0,
96
+ **kw: Any,
97
+ ) -> Dict[str, Any]:
98
+ """Transit House. Requires transit date + location; time defaults to 00:00:00."""
99
+ payload = self._birth(**kw)
100
+ payload.update(self._transit_dt(
101
+ transit_day, transit_month, transit_year,
102
+ transit_hour, transit_min, transit_sec,
103
+ ))
104
+ payload.update(self._transit_loc(
105
+ transit_lat, transit_lon, transit_tzone, transit_place,
106
+ ))
107
+ return self._c.post("astroapi-4", "/western-api/v1/transit/house", payload)
108
+
109
+ # ------------------------------------------------------------------ #
110
+ # astroapi-8 transit endpoints
111
+ # ------------------------------------------------------------------ #
112
+
113
+ def monthly(
114
+ self,
115
+ transit_planet: str, transit_month: int, transit_year: int,
116
+ transit_lat: float, transit_lon: float,
117
+ transit_tzone: float, transit_place: str,
118
+ **kw: Any,
119
+ ) -> Dict[str, Any]:
120
+ """Transit Monthly. Requires the transiting planet, month, year and location."""
121
+ payload = self._birth(**kw)
122
+ payload.update({
123
+ "transit_planet": transit_planet,
124
+ "transit_month": transit_month, "transit_year": transit_year,
125
+ })
126
+ payload.update(self._transit_loc(
127
+ transit_lat, transit_lon, transit_tzone, transit_place,
128
+ ))
129
+ return self._c.post("astroapi-8", "/western-api/v2/transit/monthly", payload)
130
+
131
+ def full(
132
+ self,
133
+ transit_planet: str,
134
+ transit_day: int, transit_month: int, transit_year: int,
135
+ transit_lat: float, transit_lon: float,
136
+ transit_tzone: float, transit_place: str,
137
+ transit_hour: int = 0, transit_min: int = 0, transit_sec: int = 0,
138
+ **kw: Any,
139
+ ) -> Dict[str, Any]:
140
+ """Full Transit. Requires the transiting planet, transit date and location."""
141
+ payload = self._birth(**kw)
142
+ payload["transit_planet"] = transit_planet
143
+ payload.update(self._transit_dt(
144
+ transit_day, transit_month, transit_year,
145
+ transit_hour, transit_min, transit_sec,
146
+ ))
147
+ payload.update(self._transit_loc(
148
+ transit_lat, transit_lon, transit_tzone, transit_place,
149
+ ))
150
+ return self._c.post("astroapi-8", "/western-api/v1/full-transit", payload)
151
+
152
+ def planet_retrograde(
153
+ self, planet: str, month: int, year: int,
154
+ place: str, lat: float, lon: float, tzone: float,
155
+ ) -> Dict[str, Any]:
156
+ """Planet Retrograde Transit."""
157
+ return self._c.post("astroapi-8", "/western-api/v1/planet-retrograde-transit", {
158
+ "planet": planet, "month": month, "year": year,
159
+ "place": place, "lat": lat, "lon": lon, "tzone": tzone,
160
+ })
161
+
162
+ def planetary_ingress(
163
+ self, planet: str, month: int, year: int,
164
+ place: str, lat: float, lon: float, tzone: float,
165
+ ) -> Dict[str, Any]:
166
+ """Planetary Ingress."""
167
+ return self._c.post("astroapi-8", "/western-api/v1/planetary-ingress", {
168
+ "planet": planet, "month": month, "year": year,
169
+ "place": place, "lat": lat, "lon": lon, "tzone": tzone,
170
+ })
171
+
172
+ def planet_combustion(
173
+ self, planet: str, month: int, year: int,
174
+ place: str, lat: float, lon: float, tzone: float,
175
+ ) -> Dict[str, Any]:
176
+ """Planet Combustion Transit."""
177
+ return self._c.post("astroapi-8", "/western-api/v1/planet-combustion-transit", {
178
+ "planet": planet, "month": month, "year": year,
179
+ "place": place, "lat": lat, "lon": lon, "tzone": tzone,
180
+ })
181
+
182
+ def wheel_chart(
183
+ self,
184
+ transit_day: int, transit_month: int, transit_year: int,
185
+ transit_lat: float, transit_lon: float,
186
+ transit_tzone: float, transit_place: str,
187
+ transit_hour: int = 0, transit_min: int = 0, transit_sec: int = 0,
188
+ **kw: Any,
189
+ ) -> Dict[str, Any]:
190
+ """Transit Wheel Chart. Requires transit date + location."""
191
+ payload = self._birth(**kw)
192
+ payload.update(self._transit_dt(
193
+ transit_day, transit_month, transit_year,
194
+ transit_hour, transit_min, transit_sec,
195
+ ))
196
+ payload.update(self._transit_loc(
197
+ transit_lat, transit_lon, transit_tzone, transit_place,
198
+ ))
199
+ return self._c.post("astroapi-8", "/western-api/v1/transit/wheel-chart", payload)
200
+
201
+ def planetary_positions(
202
+ self,
203
+ transit_day: int, transit_month: int, transit_year: int,
204
+ transit_lat: float, transit_lon: float,
205
+ transit_tzone: float, transit_place: str,
206
+ transit_hour: int = 0, transit_min: int = 0, transit_sec: int = 0,
207
+ **kw: Any,
208
+ ) -> Dict[str, Any]:
209
+ """Transit Planetary Positions. Requires transit date + location."""
210
+ payload = self._birth(**kw)
211
+ payload.update(self._transit_dt(
212
+ transit_day, transit_month, transit_year,
213
+ transit_hour, transit_min, transit_sec,
214
+ ))
215
+ payload.update(self._transit_loc(
216
+ transit_lat, transit_lon, transit_tzone, transit_place,
217
+ ))
218
+ return self._c.post("astroapi-8", "/western-api/v1/transit/planetary-positions", payload)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: divineapi
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: Official Python SDK for the Divine API - Astrology, Numerology, Tarot & more
5
5
  Author-email: Divine API <support@divineapi.com>
6
6
  License: MIT
@@ -51,9 +51,9 @@ from divineapi import DivineApi
51
51
 
52
52
  client = DivineApi(api_key="your-api-key", auth_token="your-bearer-token")
53
53
 
54
- # Daily Horoscope
54
+ # Daily Horoscope (h_day = today, tomorrow, or yesterday)
55
55
  result = client.horoscope.daily(
56
- sign="aries", day=10, month=3, year=2024, tzone=5.5
56
+ sign="aries", h_day="today", tzone=5.5
57
57
  )
58
58
  print(result)
59
59
  ```
@@ -64,10 +64,11 @@ print(result)
64
64
 
65
65
  ```python
66
66
  # Daily / Weekly / Monthly / Yearly Horoscope
67
- client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
68
- client.horoscope.weekly(sign="leo", week="thisweek", tzone=5.5)
69
- client.horoscope.monthly(sign="cancer", month=3, tzone=5.5)
70
- client.horoscope.yearly(sign="virgo", year=2024, tzone=5.5)
67
+ # daily h_day = today / tomorrow / yesterday; weekly/monthly/yearly = current / prev / next
68
+ client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
69
+ client.horoscope.weekly(sign="leo", week="current", tzone=5.5)
70
+ client.horoscope.monthly(sign="cancer", month="current", tzone=5.5)
71
+ client.horoscope.yearly(sign="virgo", year="current", tzone=5.5)
71
72
 
72
73
  # Chinese & Numerology Horoscope
73
74
  client.horoscope.chinese(sign="rat", h_day="today", tzone=5.5)
@@ -164,8 +165,9 @@ client.indian.festival.chaitra_festivals(
164
165
  client.indian.festival.english_calendar(
165
166
  year=2024, month=3, place="Delhi", lat=28.6, lon=77.2, tzone=5.5
166
167
  )
168
+ # festival is a lowercase snake_case slug from the Divine festival list
167
169
  client.indian.festival.find_festival(
168
- festival="diwali", year=2024,
170
+ festival="maha_shivratri", year=2024,
169
171
  place="Delhi", lat=28.6, lon=77.2, tzone=5.5
170
172
  )
171
173
  client.indian.festival.malayalam_festivals(
@@ -193,7 +195,7 @@ client.western.natal.house_cusps(**birth_w)
193
195
  client.western.natal.aspect_table(**birth_w)
194
196
  client.western.natal.natal_wheel_chart(**birth_w)
195
197
  client.western.natal.natal_insights(**birth_w)
196
- client.western.natal.dominants(method="traditional", **birth_w)
198
+ client.western.natal.dominants(method="TRADITIONAL", **birth_w)
197
199
  ```
198
200
 
199
201
  ### Western Astrology - Synastry
@@ -252,7 +254,7 @@ client.lifestyle.astro_chic_picks(sign="virgo", h_day="today", tzone=5.5)
252
254
  ### Calculators
253
255
 
254
256
  ```python
255
- client.calculators.flames(full_name="John", partner_name="Jane")
257
+ client.calculators.flames(your_name="John", partner_name="Jane")
256
258
  client.calculators.love_calculator(
257
259
  your_name="John", partner_name="Jane",
258
260
  your_gender="male", partner_gender="female",
@@ -262,11 +264,15 @@ client.calculators.love_calculator(
262
264
  ### PDF Reports
263
265
 
264
266
  ```python
267
+ # The six branding fields (company_url, logo_url, footer_text, company_name,
268
+ # company_email, company_bio) are REQUIRED by the PDF backend.
265
269
  client.pdf.kundali_sampoorna(
266
270
  full_name="John", day=1, month=1, year=1990,
267
271
  hour=10, min=30, sec=0, gender="male",
268
272
  place="Mumbai", lat=19.07, lon=72.87, tzone=5.5,
269
273
  company_name="AstroCo", company_url="https://example.com",
274
+ company_email="hello@example.com", company_bio="We do astrology.",
275
+ logo_url="https://example.com/logo.png", footer_text="(c) AstroCo",
270
276
  )
271
277
  ```
272
278
 
@@ -278,7 +284,7 @@ from divineapi import DivineApi, AuthenticationError, ValidationError, RateLimit
278
284
  client = DivineApi(api_key="...", auth_token="...")
279
285
 
280
286
  try:
281
- result = client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
287
+ result = client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
282
288
  except AuthenticationError as e:
283
289
  print(f"Auth failed: {e}")
284
290
  except ValidationError as e:
@@ -291,7 +297,7 @@ except RateLimitError as e:
291
297
 
292
298
  ```python
293
299
  with DivineApi(api_key="...", auth_token="...") as client:
294
- result = client.horoscope.daily(sign="aries", day=10, month=3, year=2024, tzone=5.5)
300
+ result = client.horoscope.daily(sign="aries", h_day="today", tzone=5.5)
295
301
  ```
296
302
 
297
303
  ## Configuration
@@ -22,6 +22,7 @@ divineapi/indian/kundli.py
22
22
  divineapi/indian/match_making.py
23
23
  divineapi/indian/panchang.py
24
24
  divineapi/western/__init__.py
25
+ divineapi/western/_house_system.py
25
26
  divineapi/western/composite.py
26
27
  divineapi/western/natal.py
27
28
  divineapi/western/planet_returns.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "divineapi"
7
- version = "1.2.0"
7
+ version = "1.3.0"
8
8
  description = "Official Python SDK for the Divine API - Astrology, Numerology, Tarot & more"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1,110 +0,0 @@
1
- """Western API - Transit endpoints (astroapi-4 and astroapi-8)."""
2
-
3
- from typing import Any, Dict
4
-
5
- from ..client import BaseClient
6
-
7
-
8
- class TransitApi:
9
- """Transit endpoints for Western astrology."""
10
-
11
- def __init__(self, client: BaseClient) -> None:
12
- self._c = client
13
-
14
- # ------------------------------------------------------------------ #
15
- # Birth-data helper
16
- # ------------------------------------------------------------------ #
17
-
18
- @staticmethod
19
- def _birth(
20
- full_name: str, day: int, month: int, year: int,
21
- hour: int, min: int, sec: int, gender: str,
22
- place: str, lat: float, lon: float, tzone: float,
23
- lan: str = "en", house_system: str = "placidus",
24
- **extra: Any,
25
- ) -> Dict[str, Any]:
26
- d: Dict[str, Any] = {
27
- "full_name": full_name, "day": day, "month": month, "year": year,
28
- "hour": hour, "min": min, "sec": sec, "gender": gender,
29
- "place": place, "lat": lat, "lon": lon, "tzone": tzone,
30
- "lan": lan, "house_system": house_system,
31
- }
32
- d.update(extra)
33
- return d
34
-
35
- def _post4(self, path: str, **kw: Any) -> Dict[str, Any]:
36
- return self._c.post("astroapi-4", path, self._birth(**kw))
37
-
38
- def _post8(self, path: str, **kw: Any) -> Dict[str, Any]:
39
- return self._c.post("astroapi-8", path, self._birth(**kw))
40
-
41
- # ------------------------------------------------------------------ #
42
- # astroapi-4 transit endpoints
43
- # ------------------------------------------------------------------ #
44
-
45
- def basic(self, **kw: Any) -> Dict[str, Any]:
46
- """Transit Basic (pass transit_day/month/year/hour/min/sec via **kw)."""
47
- return self._post4("/western-api/v1/transit/basic", **kw)
48
-
49
- def daily(self, **kw: Any) -> Dict[str, Any]:
50
- """Transit Daily."""
51
- return self._post4("/western-api/v1/transit/daily", **kw)
52
-
53
- def weekly(self, transit_planet: str, **kw: Any) -> Dict[str, Any]:
54
- """Transit Weekly."""
55
- kw["transit_planet"] = transit_planet
56
- return self._post4("/western-api/v1/transit/weekly", **kw)
57
-
58
- def house(self, **kw: Any) -> Dict[str, Any]:
59
- """Transit House (pass full transit params via **kw)."""
60
- return self._post4("/western-api/v1/transit/house", **kw)
61
-
62
- # ------------------------------------------------------------------ #
63
- # astroapi-8 transit endpoints
64
- # ------------------------------------------------------------------ #
65
-
66
- def monthly(self, **kw: Any) -> Dict[str, Any]:
67
- """Transit Monthly (pass extensive transit params via **kw)."""
68
- return self._post8("/western-api/v2/transit/monthly", **kw)
69
-
70
- def full(self, **kw: Any) -> Dict[str, Any]:
71
- """Full Transit (pass extensive transit params via **kw)."""
72
- return self._post8("/western-api/v1/full-transit", **kw)
73
-
74
- def planet_retrograde(
75
- self, planet: str, month: int, year: int,
76
- place: str, lat: float, lon: float, tzone: float,
77
- ) -> Dict[str, Any]:
78
- """Planet Retrograde Transit."""
79
- return self._c.post("astroapi-8", "/western-api/v1/planet-retrograde-transit", {
80
- "planet": planet, "month": month, "year": year,
81
- "place": place, "lat": lat, "lon": lon, "tzone": tzone,
82
- })
83
-
84
- def planetary_ingress(
85
- self, planet: str, month: int, year: int,
86
- place: str, lat: float, lon: float, tzone: float,
87
- ) -> Dict[str, Any]:
88
- """Planetary Ingress."""
89
- return self._c.post("astroapi-8", "/western-api/v1/planetary-ingress", {
90
- "planet": planet, "month": month, "year": year,
91
- "place": place, "lat": lat, "lon": lon, "tzone": tzone,
92
- })
93
-
94
- def planet_combustion(
95
- self, planet: str, month: int, year: int,
96
- place: str, lat: float, lon: float, tzone: float,
97
- ) -> Dict[str, Any]:
98
- """Planet Combustion Transit."""
99
- return self._c.post("astroapi-8", "/western-api/v1/planet-combustion-transit", {
100
- "planet": planet, "month": month, "year": year,
101
- "place": place, "lat": lat, "lon": lon, "tzone": tzone,
102
- })
103
-
104
- def wheel_chart(self, **kw: Any) -> Dict[str, Any]:
105
- """Transit Wheel Chart."""
106
- return self._post8("/western-api/v1/transit/wheel-chart", **kw)
107
-
108
- def planetary_positions(self, **kw: Any) -> Dict[str, Any]:
109
- """Transit Planetary Positions."""
110
- return self._post8("/western-api/v1/transit/planetary-positions", **kw)
File without changes
File without changes
File without changes
File without changes
File without changes