divineapi 1.1.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.1.0 → divineapi-1.3.0}/PKG-INFO +21 -12
  2. {divineapi-1.1.0 → divineapi-1.3.0}/README.md +20 -11
  3. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/__init__.py +6 -4
  4. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/calculators.py +2 -2
  5. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/horoscope.py +27 -11
  6. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/indian/festival.py +8 -0
  7. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/pdf.py +23 -16
  8. divineapi-1.3.0/divineapi/western/_house_system.py +52 -0
  9. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/western/composite.py +2 -1
  10. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/western/natal.py +5 -4
  11. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/western/planet_returns.py +5 -3
  12. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/western/prenatal.py +2 -1
  13. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/western/progressions.py +16 -5
  14. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/western/synastry.py +2 -1
  15. divineapi-1.3.0/divineapi/western/transit.py +218 -0
  16. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi.egg-info/PKG-INFO +21 -12
  17. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi.egg-info/SOURCES.txt +1 -0
  18. {divineapi-1.1.0 → divineapi-1.3.0}/pyproject.toml +1 -1
  19. divineapi-1.1.0/divineapi/western/transit.py +0 -110
  20. {divineapi-1.1.0 → divineapi-1.3.0}/LICENSE +0 -0
  21. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/client.py +0 -0
  22. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/exceptions.py +0 -0
  23. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/indian/__init__.py +0 -0
  24. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/indian/kundli.py +0 -0
  25. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/indian/match_making.py +0 -0
  26. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/indian/panchang.py +0 -0
  27. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/lifestyle.py +0 -0
  28. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/numerology.py +0 -0
  29. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/py.typed +0 -0
  30. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi/western/__init__.py +0 -0
  31. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi.egg-info/dependency_links.txt +0 -0
  32. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi.egg-info/requires.txt +0 -0
  33. {divineapi-1.1.0 → divineapi-1.3.0}/divineapi.egg-info/top_level.txt +0 -0
  34. {divineapi-1.1.0 → divineapi-1.3.0}/setup.cfg +0 -0
  35. {divineapi-1.1.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.1.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(
@@ -174,6 +176,9 @@ client.indian.festival.malayalam_festivals(
174
176
  client.indian.festival.tamil_festivals(
175
177
  year=2027, place="Chennai", lat=13.0827, lon=80.2707, tzone=5.5
176
178
  )
179
+ client.indian.festival.sankranti_festivals(
180
+ year=2027, place="New Delhi", lat=28.6139, lon=77.2090, tzone=5.5
181
+ )
177
182
  ```
178
183
 
179
184
  ### Western Astrology - Natal
@@ -190,7 +195,7 @@ client.western.natal.house_cusps(**birth_w)
190
195
  client.western.natal.aspect_table(**birth_w)
191
196
  client.western.natal.natal_wheel_chart(**birth_w)
192
197
  client.western.natal.natal_insights(**birth_w)
193
- client.western.natal.dominants(method="traditional", **birth_w)
198
+ client.western.natal.dominants(method="TRADITIONAL", **birth_w)
194
199
  ```
195
200
 
196
201
  ### Western Astrology - Synastry
@@ -249,7 +254,7 @@ client.lifestyle.astro_chic_picks(sign="virgo", h_day="today", tzone=5.5)
249
254
  ### Calculators
250
255
 
251
256
  ```python
252
- client.calculators.flames(full_name="John", partner_name="Jane")
257
+ client.calculators.flames(your_name="John", partner_name="Jane")
253
258
  client.calculators.love_calculator(
254
259
  your_name="John", partner_name="Jane",
255
260
  your_gender="male", partner_gender="female",
@@ -259,11 +264,15 @@ client.calculators.love_calculator(
259
264
  ### PDF Reports
260
265
 
261
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.
262
269
  client.pdf.kundali_sampoorna(
263
270
  full_name="John", day=1, month=1, year=1990,
264
271
  hour=10, min=30, sec=0, gender="male",
265
272
  place="Mumbai", lat=19.07, lon=72.87, tzone=5.5,
266
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",
267
276
  )
268
277
  ```
269
278
 
@@ -275,7 +284,7 @@ from divineapi import DivineApi, AuthenticationError, ValidationError, RateLimit
275
284
  client = DivineApi(api_key="...", auth_token="...")
276
285
 
277
286
  try:
278
- 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)
279
288
  except AuthenticationError as e:
280
289
  print(f"Auth failed: {e}")
281
290
  except ValidationError as e:
@@ -288,7 +297,7 @@ except RateLimitError as e:
288
297
 
289
298
  ```python
290
299
  with DivineApi(api_key="...", auth_token="...") as client:
291
- 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)
292
301
  ```
293
302
 
294
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(
@@ -146,6 +148,9 @@ client.indian.festival.malayalam_festivals(
146
148
  client.indian.festival.tamil_festivals(
147
149
  year=2027, place="Chennai", lat=13.0827, lon=80.2707, tzone=5.5
148
150
  )
151
+ client.indian.festival.sankranti_festivals(
152
+ year=2027, place="New Delhi", lat=28.6139, lon=77.2090, tzone=5.5
153
+ )
149
154
  ```
150
155
 
151
156
  ### Western Astrology - Natal
@@ -162,7 +167,7 @@ client.western.natal.house_cusps(**birth_w)
162
167
  client.western.natal.aspect_table(**birth_w)
163
168
  client.western.natal.natal_wheel_chart(**birth_w)
164
169
  client.western.natal.natal_insights(**birth_w)
165
- client.western.natal.dominants(method="traditional", **birth_w)
170
+ client.western.natal.dominants(method="TRADITIONAL", **birth_w)
166
171
  ```
167
172
 
168
173
  ### Western Astrology - Synastry
@@ -221,7 +226,7 @@ client.lifestyle.astro_chic_picks(sign="virgo", h_day="today", tzone=5.5)
221
226
  ### Calculators
222
227
 
223
228
  ```python
224
- client.calculators.flames(full_name="John", partner_name="Jane")
229
+ client.calculators.flames(your_name="John", partner_name="Jane")
225
230
  client.calculators.love_calculator(
226
231
  your_name="John", partner_name="Jane",
227
232
  your_gender="male", partner_gender="female",
@@ -231,11 +236,15 @@ client.calculators.love_calculator(
231
236
  ### PDF Reports
232
237
 
233
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.
234
241
  client.pdf.kundali_sampoorna(
235
242
  full_name="John", day=1, month=1, year=1990,
236
243
  hour=10, min=30, sec=0, gender="male",
237
244
  place="Mumbai", lat=19.07, lon=72.87, tzone=5.5,
238
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",
239
248
  )
240
249
  ```
241
250
 
@@ -247,7 +256,7 @@ from divineapi import DivineApi, AuthenticationError, ValidationError, RateLimit
247
256
  client = DivineApi(api_key="...", auth_token="...")
248
257
 
249
258
  try:
250
- 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)
251
260
  except AuthenticationError as e:
252
261
  print(f"Auth failed: {e}")
253
262
  except ValidationError as e:
@@ -260,7 +269,7 @@ except RateLimitError as e:
260
269
 
261
270
  ```python
262
271
  with DivineApi(api_key="...", auth_token="...") as client:
263
- 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)
264
273
  ```
265
274
 
266
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.1.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
  })
@@ -129,3 +129,11 @@ class FestivalApi:
129
129
  """Tamil Festivals for a year."""
130
130
  return self._c.post(HOST, "/indian-api/v1/tamil-festivals",
131
131
  self._festival_loc(year, place, lat, lon, tzone))
132
+
133
+ def sankranti_festivals(
134
+ self, year: int,
135
+ place: str, lat: float, lon: float, tzone: float,
136
+ ) -> Dict[str, Any]:
137
+ """Sankranti Festivals for a year."""
138
+ return self._c.post(HOST, "/indian-api/v1/sankranti-festivals",
139
+ self._festival_loc(year, place, lat, lon, tzone))
@@ -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.1.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(
@@ -174,6 +176,9 @@ client.indian.festival.malayalam_festivals(
174
176
  client.indian.festival.tamil_festivals(
175
177
  year=2027, place="Chennai", lat=13.0827, lon=80.2707, tzone=5.5
176
178
  )
179
+ client.indian.festival.sankranti_festivals(
180
+ year=2027, place="New Delhi", lat=28.6139, lon=77.2090, tzone=5.5
181
+ )
177
182
  ```
178
183
 
179
184
  ### Western Astrology - Natal
@@ -190,7 +195,7 @@ client.western.natal.house_cusps(**birth_w)
190
195
  client.western.natal.aspect_table(**birth_w)
191
196
  client.western.natal.natal_wheel_chart(**birth_w)
192
197
  client.western.natal.natal_insights(**birth_w)
193
- client.western.natal.dominants(method="traditional", **birth_w)
198
+ client.western.natal.dominants(method="TRADITIONAL", **birth_w)
194
199
  ```
195
200
 
196
201
  ### Western Astrology - Synastry
@@ -249,7 +254,7 @@ client.lifestyle.astro_chic_picks(sign="virgo", h_day="today", tzone=5.5)
249
254
  ### Calculators
250
255
 
251
256
  ```python
252
- client.calculators.flames(full_name="John", partner_name="Jane")
257
+ client.calculators.flames(your_name="John", partner_name="Jane")
253
258
  client.calculators.love_calculator(
254
259
  your_name="John", partner_name="Jane",
255
260
  your_gender="male", partner_gender="female",
@@ -259,11 +264,15 @@ client.calculators.love_calculator(
259
264
  ### PDF Reports
260
265
 
261
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.
262
269
  client.pdf.kundali_sampoorna(
263
270
  full_name="John", day=1, month=1, year=1990,
264
271
  hour=10, min=30, sec=0, gender="male",
265
272
  place="Mumbai", lat=19.07, lon=72.87, tzone=5.5,
266
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",
267
276
  )
268
277
  ```
269
278
 
@@ -275,7 +284,7 @@ from divineapi import DivineApi, AuthenticationError, ValidationError, RateLimit
275
284
  client = DivineApi(api_key="...", auth_token="...")
276
285
 
277
286
  try:
278
- 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)
279
288
  except AuthenticationError as e:
280
289
  print(f"Auth failed: {e}")
281
290
  except ValidationError as e:
@@ -288,7 +297,7 @@ except RateLimitError as e:
288
297
 
289
298
  ```python
290
299
  with DivineApi(api_key="...", auth_token="...") as client:
291
- 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)
292
301
  ```
293
302
 
294
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.1.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