diff --git a/README.md b/README.md index a67aa71..78261cf 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,14 @@ Or chart.show() sys.exit(App.exec()) ``` + +Alternatively a PySide6 based interface is available: + +``` + from pyside_app.main import main + if __name__ == "__main__": + main() +``` Using the GUI ------------- @@ -807,3 +815,8 @@ See LICENSE file. Contact ------- https://github.com/naturalstupid/ + +FastAPI Backend +--------------- +A lightweight API implementation using FastAPI is available in `src/astroapi`. Run `uvicorn astroapi.main:app --reload` to start the server. +For a browser-based UI, open `frontend/index.html` with any static file server. diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..a74fbbd --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,91 @@ + + + + + + AstroCal Chart + + + + + + +
+ + + + diff --git a/requirements.txt b/requirements.txt index 196676c..23beabc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ attr==0.3.2 -conda==4.3.16 geocoder==1.38.1 geopy==2.4.1 img2pdf==0.5.1 @@ -9,13 +8,16 @@ Pillow==11.1.0 pyephem==9.99 PyQt6==6.8.1 PyQt6_sip==13.8.0 +PySide6==6.7.0 pyqtgraph==0.13.7 pyswisseph==2.10.3.2 pytest==7.4.4 -pytest.egg==info python_dateutil==2.9.0.post0 pytz==2024.1 Requests==2.32.3 -setuptools==69.5.1 setuptools==75.6.0 timezonefinder==6.5.8 + +fastapi==0.111.0 +uvicorn==0.29.0 +pydantic==2.7.1 diff --git a/src/astroapi/README.md b/src/astroapi/README.md new file mode 100644 index 0000000..9fa6c41 --- /dev/null +++ b/src/astroapi/README.md @@ -0,0 +1,31 @@ +# AstroCal FastAPI Backend + +This module exposes horoscope computations via a simple REST API. + +## Endpoints + +- `GET /health` – basic health check +- `POST /chart` or `/generate_chart` – compute a Vedic horoscope + +### Example request + +```json +{ + "name": "John Doe", + "gender": "M", + "birth_date": "2000-01-01", + "birth_time": "12:34:00", + "place": "Chennai, India", + "latitude": 13.0827, + "longitude": 80.2707, + "timezone": 5.5 +} +``` + +Start the API with: + +```bash +uvicorn astroapi.main:app --reload +``` + +The response contains horoscope information ready for client consumption. diff --git a/src/astroapi/__init__.py b/src/astroapi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/astroapi/__main__.py b/src/astroapi/__main__.py new file mode 100644 index 0000000..ee313f4 --- /dev/null +++ b/src/astroapi/__main__.py @@ -0,0 +1,5 @@ +from .main import app + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/src/astroapi/main.py b/src/astroapi/main.py new file mode 100644 index 0000000..170cf9d --- /dev/null +++ b/src/astroapi/main.py @@ -0,0 +1,22 @@ +"""FastAPI application exposing horoscope computation endpoints.""" +from fastapi import FastAPI, HTTPException + +from .models import ChartRequest +from .services import compute_chart + +app = FastAPI(title="AstroCal API") + +@app.get("/health") +def health_check(): + """Simple health check endpoint.""" + return {"status": "ok"} + +@app.post("/chart") +@app.post("/generate_chart") +def generate_chart(request: ChartRequest): + """Compute a Vedic horoscope and return detailed data.""" + try: + return compute_chart(request) + except Exception as exc: + raise HTTPException(status_code=500, detail=str(exc)) + diff --git a/src/astroapi/models.py b/src/astroapi/models.py new file mode 100644 index 0000000..7b7c8c5 --- /dev/null +++ b/src/astroapi/models.py @@ -0,0 +1,14 @@ +from datetime import date, time +from pydantic import BaseModel + +class ChartRequest(BaseModel): + """Parameters required to compute a horoscope chart.""" + name: str + gender: str + birth_date: date + birth_time: time + place: str + latitude: float + longitude: float + timezone: float + diff --git a/src/astroapi/services.py b/src/astroapi/services.py new file mode 100644 index 0000000..9c8516e --- /dev/null +++ b/src/astroapi/services.py @@ -0,0 +1,37 @@ +"""Utility functions for computing horoscope information.""" +from datetime import datetime +from typing import Dict, Any + +from jhora.horoscope import main +from jhora.panchanga import drik + +from .models import ChartRequest + + +def compute_chart(request: ChartRequest) -> Dict[str, Any]: + """Generate horoscope data using existing jhora classes.""" + dob = drik.Date(request.birth_date.year, request.birth_date.month, request.birth_date.day) + tob = (request.birth_time.hour, request.birth_time.minute, request.birth_time.second) + place = drik.Place(request.place, request.latitude, request.longitude, request.timezone) + + horo = main.Horoscope( + place_with_country_code=request.place, + latitude=request.latitude, + longitude=request.longitude, + timezone_offset=request.timezone, + date_in=dob, + birth_time=request.birth_time.strftime("%H:%M:%S"), + ) + + info, charts, houses = horo.get_horoscope_information() + vimsottari = horo._get_vimsottari_dhasa_bhukthi(dob, tob, place) + + return { + "name": request.name, + "gender": request.gender, + "info": info, + "charts": charts, + "ascendant_houses": houses, + "vimsottari_dhasa": vimsottari, + } + diff --git a/src/jhora/__pycache__/__init__.cpython-311.pyc b/src/jhora/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..b53fe06 Binary files /dev/null and b/src/jhora/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/jhora/__pycache__/_package_info.cpython-311.pyc b/src/jhora/__pycache__/_package_info.cpython-311.pyc new file mode 100644 index 0000000..bf74b95 Binary files /dev/null and b/src/jhora/__pycache__/_package_info.cpython-311.pyc differ diff --git a/src/jhora/__pycache__/const.cpython-311.pyc b/src/jhora/__pycache__/const.cpython-311.pyc new file mode 100644 index 0000000..f87e265 Binary files /dev/null and b/src/jhora/__pycache__/const.cpython-311.pyc differ diff --git a/src/jhora/__pycache__/utils.cpython-311.pyc b/src/jhora/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000..355faa3 Binary files /dev/null and b/src/jhora/__pycache__/utils.cpython-311.pyc differ diff --git a/src/jhora/horoscope/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..af095bc Binary files /dev/null and b/src/jhora/horoscope/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/jhora/horoscope/__pycache__/main.cpython-311.pyc b/src/jhora/horoscope/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000..b494d35 Binary files /dev/null and b/src/jhora/horoscope/__pycache__/main.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..2725695 Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/arudhas.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/arudhas.cpython-311.pyc new file mode 100644 index 0000000..45ae1f7 Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/arudhas.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/ashtakavarga.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/ashtakavarga.cpython-311.pyc new file mode 100644 index 0000000..37ae7ca Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/ashtakavarga.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/charts.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/charts.cpython-311.pyc new file mode 100644 index 0000000..4ace7d4 Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/charts.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/dosha.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/dosha.cpython-311.pyc new file mode 100644 index 0000000..55eba83 Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/dosha.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/house.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/house.cpython-311.pyc new file mode 100644 index 0000000..b793a3f Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/house.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/raja_yoga.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/raja_yoga.cpython-311.pyc new file mode 100644 index 0000000..43b4348 Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/raja_yoga.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/sphuta.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/sphuta.cpython-311.pyc new file mode 100644 index 0000000..b62cf78 Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/sphuta.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/strength.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/strength.cpython-311.pyc new file mode 100644 index 0000000..2e46ed5 Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/strength.cpython-311.pyc differ diff --git a/src/jhora/horoscope/chart/__pycache__/yoga.cpython-311.pyc b/src/jhora/horoscope/chart/__pycache__/yoga.cpython-311.pyc new file mode 100644 index 0000000..e962fa7 Binary files /dev/null and b/src/jhora/horoscope/chart/__pycache__/yoga.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/dhasa/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..8de1da1 Binary files /dev/null and b/src/jhora/horoscope/dhasa/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/__pycache__/sudharsana_chakra.cpython-311.pyc b/src/jhora/horoscope/dhasa/__pycache__/sudharsana_chakra.cpython-311.pyc new file mode 100644 index 0000000..7e93926 Binary files /dev/null and b/src/jhora/horoscope/dhasa/__pycache__/sudharsana_chakra.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/annual/__pycache__/mudda.cpython-311.pyc b/src/jhora/horoscope/dhasa/annual/__pycache__/mudda.cpython-311.pyc new file mode 100644 index 0000000..9b373cb Binary files /dev/null and b/src/jhora/horoscope/dhasa/annual/__pycache__/mudda.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/annual/__pycache__/patyayini.cpython-311.pyc b/src/jhora/horoscope/dhasa/annual/__pycache__/patyayini.cpython-311.pyc new file mode 100644 index 0000000..41dedda Binary files /dev/null and b/src/jhora/horoscope/dhasa/annual/__pycache__/patyayini.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/aayu.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/aayu.cpython-311.pyc new file mode 100644 index 0000000..180a03b Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/aayu.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/ashtottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/ashtottari.cpython-311.pyc new file mode 100644 index 0000000..efb65c7 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/ashtottari.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/buddhi_gathi.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/buddhi_gathi.cpython-311.pyc new file mode 100644 index 0000000..bf52271 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/buddhi_gathi.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/chathuraaseethi_sama.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/chathuraaseethi_sama.cpython-311.pyc new file mode 100644 index 0000000..1c07d74 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/chathuraaseethi_sama.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/dwadasottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/dwadasottari.cpython-311.pyc new file mode 100644 index 0000000..da46674 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/dwadasottari.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/dwisatpathi.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/dwisatpathi.cpython-311.pyc new file mode 100644 index 0000000..8280a0b Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/dwisatpathi.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/kaala.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/kaala.cpython-311.pyc new file mode 100644 index 0000000..ea4c468 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/kaala.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/karaka.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/karaka.cpython-311.pyc new file mode 100644 index 0000000..1e267fc Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/karaka.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/karana_chathuraaseethi_sama.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/karana_chathuraaseethi_sama.cpython-311.pyc new file mode 100644 index 0000000..e7f57ff Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/karana_chathuraaseethi_sama.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/naisargika.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/naisargika.cpython-311.pyc new file mode 100644 index 0000000..3cea667 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/naisargika.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/panchottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/panchottari.cpython-311.pyc new file mode 100644 index 0000000..719db84 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/panchottari.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/saptharishi_nakshathra.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/saptharishi_nakshathra.cpython-311.pyc new file mode 100644 index 0000000..66c6a58 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/saptharishi_nakshathra.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/sataatbika.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/sataatbika.cpython-311.pyc new file mode 100644 index 0000000..6a91d58 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/sataatbika.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/shastihayani.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/shastihayani.cpython-311.pyc new file mode 100644 index 0000000..08714ac Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/shastihayani.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/shattrimsa_sama.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/shattrimsa_sama.cpython-311.pyc new file mode 100644 index 0000000..a436298 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/shattrimsa_sama.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/shodasottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/shodasottari.cpython-311.pyc new file mode 100644 index 0000000..0713a6d Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/shodasottari.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/tara.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/tara.cpython-311.pyc new file mode 100644 index 0000000..40cfc2c Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/tara.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_ashtottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_ashtottari.cpython-311.pyc new file mode 100644 index 0000000..03677b7 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_ashtottari.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_yogini.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_yogini.cpython-311.pyc new file mode 100644 index 0000000..5dd6771 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/tithi_yogini.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/vimsottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/vimsottari.cpython-311.pyc new file mode 100644 index 0000000..90b0ef2 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/vimsottari.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/yoga_vimsottari.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/yoga_vimsottari.cpython-311.pyc new file mode 100644 index 0000000..d9f81c4 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/yoga_vimsottari.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/graha/__pycache__/yogini.cpython-311.pyc b/src/jhora/horoscope/dhasa/graha/__pycache__/yogini.cpython-311.pyc new file mode 100644 index 0000000..3888828 Binary files /dev/null and b/src/jhora/horoscope/dhasa/graha/__pycache__/yogini.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/brahma.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/brahma.cpython-311.pyc new file mode 100644 index 0000000..f0c8907 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/brahma.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/chakra.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/chakra.cpython-311.pyc new file mode 100644 index 0000000..e865cfb Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/chakra.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/chara.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/chara.cpython-311.pyc new file mode 100644 index 0000000..c7e70fb Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/chara.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/drig.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/drig.cpython-311.pyc new file mode 100644 index 0000000..56c0e16 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/drig.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/kalachakra.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/kalachakra.cpython-311.pyc new file mode 100644 index 0000000..48be3cb Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/kalachakra.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/kendradhi_rasi.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/kendradhi_rasi.cpython-311.pyc new file mode 100644 index 0000000..b2db59f Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/kendradhi_rasi.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/lagnamsaka.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/lagnamsaka.cpython-311.pyc new file mode 100644 index 0000000..45da1de Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/lagnamsaka.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/mandooka.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/mandooka.cpython-311.pyc new file mode 100644 index 0000000..f3b1b92 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/mandooka.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/narayana.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/narayana.cpython-311.pyc new file mode 100644 index 0000000..7159889 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/narayana.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/navamsa.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/navamsa.cpython-311.pyc new file mode 100644 index 0000000..26f723c Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/navamsa.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/nirayana.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/nirayana.cpython-311.pyc new file mode 100644 index 0000000..bca9b90 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/nirayana.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/padhanadhamsa.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/padhanadhamsa.cpython-311.pyc new file mode 100644 index 0000000..c895dc2 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/padhanadhamsa.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/paryaaya.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/paryaaya.cpython-311.pyc new file mode 100644 index 0000000..e872629 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/paryaaya.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/sandhya.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/sandhya.cpython-311.pyc new file mode 100644 index 0000000..6e80dff Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/sandhya.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/shoola.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/shoola.cpython-311.pyc new file mode 100644 index 0000000..f46a40e Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/shoola.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/sthira.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/sthira.cpython-311.pyc new file mode 100644 index 0000000..00252f7 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/sthira.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/sudasa.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/sudasa.cpython-311.pyc new file mode 100644 index 0000000..67fc7e7 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/sudasa.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/tara_lagna.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/tara_lagna.cpython-311.pyc new file mode 100644 index 0000000..de826fa Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/tara_lagna.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/trikona.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/trikona.cpython-311.pyc new file mode 100644 index 0000000..2c807ca Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/trikona.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/varnada.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/varnada.cpython-311.pyc new file mode 100644 index 0000000..933b68d Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/varnada.cpython-311.pyc differ diff --git a/src/jhora/horoscope/dhasa/raasi/__pycache__/yogardha.cpython-311.pyc b/src/jhora/horoscope/dhasa/raasi/__pycache__/yogardha.cpython-311.pyc new file mode 100644 index 0000000..8f00828 Binary files /dev/null and b/src/jhora/horoscope/dhasa/raasi/__pycache__/yogardha.cpython-311.pyc differ diff --git a/src/jhora/horoscope/match/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/match/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..5403620 Binary files /dev/null and b/src/jhora/horoscope/match/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/jhora/horoscope/match/__pycache__/compatibility.cpython-311.pyc b/src/jhora/horoscope/match/__pycache__/compatibility.cpython-311.pyc new file mode 100644 index 0000000..d38fba1 Binary files /dev/null and b/src/jhora/horoscope/match/__pycache__/compatibility.cpython-311.pyc differ diff --git a/src/jhora/horoscope/prediction/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/prediction/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..afc3fff Binary files /dev/null and b/src/jhora/horoscope/prediction/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/jhora/horoscope/prediction/__pycache__/general.cpython-311.pyc b/src/jhora/horoscope/prediction/__pycache__/general.cpython-311.pyc new file mode 100644 index 0000000..3ad9c6b Binary files /dev/null and b/src/jhora/horoscope/prediction/__pycache__/general.cpython-311.pyc differ diff --git a/src/jhora/horoscope/transit/__pycache__/__init__.cpython-311.pyc b/src/jhora/horoscope/transit/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..425a8f0 Binary files /dev/null and b/src/jhora/horoscope/transit/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/jhora/horoscope/transit/__pycache__/saham.cpython-311.pyc b/src/jhora/horoscope/transit/__pycache__/saham.cpython-311.pyc new file mode 100644 index 0000000..14bc566 Binary files /dev/null and b/src/jhora/horoscope/transit/__pycache__/saham.cpython-311.pyc differ diff --git a/src/jhora/panchanga/__pycache__/__init__.cpython-311.pyc b/src/jhora/panchanga/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..c78f5de Binary files /dev/null and b/src/jhora/panchanga/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/jhora/panchanga/__pycache__/drik.cpython-311.pyc b/src/jhora/panchanga/__pycache__/drik.cpython-311.pyc new file mode 100644 index 0000000..98bc45f Binary files /dev/null and b/src/jhora/panchanga/__pycache__/drik.cpython-311.pyc differ diff --git a/src/jhora/panchanga/__pycache__/pancha_paksha.cpython-311.pyc b/src/jhora/panchanga/__pycache__/pancha_paksha.cpython-311.pyc new file mode 100644 index 0000000..5b1b9a2 Binary files /dev/null and b/src/jhora/panchanga/__pycache__/pancha_paksha.cpython-311.pyc differ diff --git a/src/jhora/panchanga/__pycache__/surya_sidhantha.cpython-311.pyc b/src/jhora/panchanga/__pycache__/surya_sidhantha.cpython-311.pyc new file mode 100644 index 0000000..f76cbc9 Binary files /dev/null and b/src/jhora/panchanga/__pycache__/surya_sidhantha.cpython-311.pyc differ diff --git a/src/jhora/panchanga/__pycache__/vratha.cpython-311.pyc b/src/jhora/panchanga/__pycache__/vratha.cpython-311.pyc new file mode 100644 index 0000000..e1b51af Binary files /dev/null and b/src/jhora/panchanga/__pycache__/vratha.cpython-311.pyc differ diff --git a/src/jhora/requirements.txt b/src/jhora/requirements.txt index 1d1269b..b570b1a 100644 --- a/src/jhora/requirements.txt +++ b/src/jhora/requirements.txt @@ -6,6 +6,7 @@ numpy==2.1.1 pandas==2.2.2 Pillow==10.4.0 PyQt6==6.7.1 +PySide6==6.7.0 pyqtgraph==0.13.7 python_dateutil==2.9.0.post0 pytz==2024.1 diff --git a/src/jhora/tests/test_ui.py b/src/jhora/tests/test_ui.py index e39d1f1..9dd550c 100644 --- a/src/jhora/tests/test_ui.py +++ b/src/jhora/tests/test_ui.py @@ -18,6 +18,10 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import pytest + +pytest.skip("Manual UI test", allow_module_level=True) + import sys from PyQt6.QtWidgets import QApplication diff --git a/src/jhora/ui/__pycache__/__init__.cpython-311.pyc b/src/jhora/ui/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..7fdfbd6 Binary files /dev/null and b/src/jhora/ui/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/chakra.cpython-311.pyc b/src/jhora/ui/__pycache__/chakra.cpython-311.pyc new file mode 100644 index 0000000..240eed7 Binary files /dev/null and b/src/jhora/ui/__pycache__/chakra.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/chart_styles.cpython-311.pyc b/src/jhora/ui/__pycache__/chart_styles.cpython-311.pyc new file mode 100644 index 0000000..d5cb99a Binary files /dev/null and b/src/jhora/ui/__pycache__/chart_styles.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/conjunction_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/conjunction_dialog.cpython-311.pyc new file mode 100644 index 0000000..d79b55a Binary files /dev/null and b/src/jhora/ui/__pycache__/conjunction_dialog.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/dhasa_bhukthi_options_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/dhasa_bhukthi_options_dialog.cpython-311.pyc new file mode 100644 index 0000000..11b877d Binary files /dev/null and b/src/jhora/ui/__pycache__/dhasa_bhukthi_options_dialog.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/horo_chart_tabs.cpython-311.pyc b/src/jhora/ui/__pycache__/horo_chart_tabs.cpython-311.pyc new file mode 100644 index 0000000..bfdbeeb Binary files /dev/null and b/src/jhora/ui/__pycache__/horo_chart_tabs.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/label_grid.cpython-311.pyc b/src/jhora/ui/__pycache__/label_grid.cpython-311.pyc new file mode 100644 index 0000000..a3eb71e Binary files /dev/null and b/src/jhora/ui/__pycache__/label_grid.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/mixed_chart_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/mixed_chart_dialog.cpython-311.pyc new file mode 100644 index 0000000..900ad51 Binary files /dev/null and b/src/jhora/ui/__pycache__/mixed_chart_dialog.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/options_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/options_dialog.cpython-311.pyc new file mode 100644 index 0000000..7dbc7fd Binary files /dev/null and b/src/jhora/ui/__pycache__/options_dialog.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/pancha_pakshi_sastra_widget.cpython-311.pyc b/src/jhora/ui/__pycache__/pancha_pakshi_sastra_widget.cpython-311.pyc new file mode 100644 index 0000000..52ef0c4 Binary files /dev/null and b/src/jhora/ui/__pycache__/pancha_pakshi_sastra_widget.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/panchangam.cpython-311.pyc b/src/jhora/ui/__pycache__/panchangam.cpython-311.pyc new file mode 100644 index 0000000..7563b39 Binary files /dev/null and b/src/jhora/ui/__pycache__/panchangam.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/varga_chart_dialog.cpython-311.pyc b/src/jhora/ui/__pycache__/varga_chart_dialog.cpython-311.pyc new file mode 100644 index 0000000..83063eb Binary files /dev/null and b/src/jhora/ui/__pycache__/varga_chart_dialog.cpython-311.pyc differ diff --git a/src/jhora/ui/__pycache__/vratha_finder.cpython-311.pyc b/src/jhora/ui/__pycache__/vratha_finder.cpython-311.pyc new file mode 100644 index 0000000..c4dd84d Binary files /dev/null and b/src/jhora/ui/__pycache__/vratha_finder.cpython-311.pyc differ diff --git a/src/jhora/ui/horo_chart_tabs.py b/src/jhora/ui/horo_chart_tabs.py index 14bf437..7839654 100644 --- a/src/jhora/ui/horo_chart_tabs.py +++ b/src/jhora/ui/horo_chart_tabs.py @@ -18,21 +18,51 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import re, sys, os -sys.path.append('../') -""" Get Package Version from _package_info.py """ -#import importlib.metadata -#_APP_VERSION = importlib.metadata.version('PyJHora') -#---------- -from PyQt6 import QtCore, QtGui -from PyQt6.QtWidgets import QStyledItemDelegate, QWidget, QVBoxLayout, QHBoxLayout, QTabWidget, QTableWidget, \ - QListWidget, QTextEdit, QAbstractItemView, QAbstractScrollArea, QTableWidgetItem, \ - QGridLayout, QLayout, QLabel, QSizePolicy, QLineEdit, QCompleter, QComboBox, \ - QPushButton, QSpinBox, QCheckBox, QApplication, QDoubleSpinBox, QHeaderView, \ - QListWidgetItem,QMessageBox, QFileDialog, QButtonGroup, QRadioButton, QStackedWidget, \ - QTreeWidget -from PyQt6.QtGui import QFont, QFontMetrics +"""PyQt6 based UI for displaying horoscope charts.""" + +import os +import re +import sys + +sys.path.append("../") + +from PyQt6 import QtGui +from PyQt6 import QtCore from PyQt6.QtCore import Qt +from PyQt6.QtGui import QFont, QFontMetrics +from PyQt6.QtWidgets import ( + QApplication, + QCompleter, + QAbstractItemView, + QGridLayout, + QAbstractScrollArea, + QButtonGroup, + QCheckBox, + QComboBox, + QDoubleSpinBox, + QFileDialog, + QLabel, + QListWidget, + QListWidgetItem, + QHBoxLayout, + QHeaderView, + QLineEdit, + QLayout, + QMessageBox, + QPushButton, + QRadioButton, + QSizePolicy, + QSpinBox, + QStackedWidget, + QStyledItemDelegate, + QTabWidget, + QTableWidget, + QTableWidgetItem, + QTextEdit, + QTreeWidget, + QVBoxLayout, + QWidget, +) from _datetime import datetime, timedelta, timezone import img2pdf from PIL import Image @@ -64,11 +94,14 @@ _images_path = const._IMAGES_PATH _IMAGES_PER_PDF_PAGE = 2 _INPUT_DATA_FILE = const._INPUT_DATA_FILE -_SHOW_GOURI_PANCHANG_OR_SHUBHA_HORA = 0 # 0=Gowri Panchang 1=Shubha Hora +_SHOW_GOURI_PANCHANG_OR_SHUBHA_HORA = 0 # 0=Gowri Panchang 1=Shubha Hora _world_city_csv_file = const._world_city_csv_file -_planet_symbols=const._planet_symbols +_planet_symbols = const._planet_symbols _zodiac_symbols = const._zodiac_symbols -""" UI Constants """ + +# --------------------------------------------------------------------------- +# UI Constants +# --------------------------------------------------------------------------- _main_window_width = 1000#750 #725 _main_window_height = 725#630 #580 # _comp_table_font_size = 8 @@ -247,60 +280,116 @@ _compatibility_tab_start = _prediction_tab_start + 1 _tab_count = len(_tab_names) -available_chart_types = {'south_indian':SouthIndianChart,'north_indian':NorthIndianChart,'east_indian':EastIndianChart, - 'western':WesternChart,'sudarsana_chakra':SudarsanaChakraChart} +available_chart_types = { + 'south_indian': SouthIndianChart, + 'north_indian': NorthIndianChart, + 'east_indian': EastIndianChart, + 'western': WesternChart, + 'sudarsana_chakra': SudarsanaChakraChart, +} available_languages = const.available_languages + +# --------------------------------------------------------------------------- +# Delegate classes +# --------------------------------------------------------------------------- class AlignDelegate(QStyledItemDelegate): + """Center-aligns text within table cells.""" + def initStyleOption(self, option, index): - super(AlignDelegate, self).initStyleOption(option, index) + super().initStyleOption(option, index) option.displayAlignment = QtCore.Qt.AlignmentFlag.AlignHCenter class GrowingTextEdit(QTextEdit): + """Text edit that grows vertically to fit its contents.""" def __init__(self, *args, **kwargs): - super(GrowingTextEdit, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.document().contentsChanged.connect(self.sizeChange) self.heightMin = 0 self.heightMax = 65000 - def sizeChange(self): - docHeight = int(self.document().size().height()) - if self.heightMin <= docHeight <= self.heightMax: - self.setMinimumHeight(docHeight) + def sizeChange(self) -> None: + doc_height = int(self.document().size().height()) + if self.heightMin <= doc_height <= self.heightMax: + self.setMinimumHeight(doc_height) + + +# --------------------------------------------------------------------------- +# Main application widget +# --------------------------------------------------------------------------- class ChartTabbed(QWidget): - def __init__(self,chart_type='south_indian',show_marriage_compatibility=True, calculation_type:str='drik', - language = 'English',date_of_birth=None,time_of_birth=None,place_of_birth=None, gender=0, - use_world_city_database=const.check_database_for_world_cities, - use_internet_for_location_check=const.use_internet_for_location_check): - """ - @param chart_type: One of 'South_Indian','North_Indian','East_Indian','Western','Sudarsana_Chakra' - Default: 'south indian' - @param date_of_birth: string in the format 'yyyy,m,d' e.g. '2024,1,1' or '2024,01,01' - @param time_of_birth: string in the format 'hh:mm:ss' in 24hr format. e.g. '19:07:04' - @param place_of_birth: tuple in the format ('place_name',latitude_float,longitude_float,timezone_hrs_float) - e.g. ('Chennai, India',13.0878,80.2785,5.5) - @param language: One of 'English','Hindi','Tamil','Telugu','Kannada'; Default:English - @param gender: 0='Female',1='Male',2='Transgender',3='No preference'; Default=0 - """ + """Main widget that hosts all horoscope related tabs.""" + + def __init__( + self, + chart_type: str = "south_indian", + show_marriage_compatibility: bool = True, + calculation_type: str = "drik", + language: str = "English", + date_of_birth: str | None = None, + time_of_birth: str | None = None, + place_of_birth: tuple | None = None, + gender: int = 0, + use_world_city_database: bool = const.check_database_for_world_cities, + use_internet_for_location_check: bool = const.use_internet_for_location_check, + ) -> None: + """Initialize the tabbed horoscope widget.""" + super().__init__() + self._initialize_state( + chart_type, + show_marriage_compatibility, + calculation_type, + language, + place_of_birth, + use_world_city_database, + use_internet_for_location_check, + ) + + self._build_ui() + self._populate_defaults(date_of_birth, time_of_birth, gender) + + # ------------------------------------------------------------------ + # Initialization helpers + # ------------------------------------------------------------------ + def _initialize_state( + self, + chart_type: str, + show_marriage_compatibility: bool, + calculation_type: str, + language: str, + place_of_birth, + use_world_city_database: bool, + use_internet_for_location_check: bool, + ) -> None: + """Set up instance variables and global settings.""" + self._horo = None self.use_world_city_database = use_world_city_database self.use_internet_for_location_check = use_internet_for_location_check - self._chart_type = chart_type if chart_type.lower() in const.available_chart_types else 'south_indian' - self._language = language; utils.set_language(available_languages[language]) + self._chart_type = ( + chart_type if chart_type.lower() in const.available_chart_types else "south_indian" + ) + self._language = language + utils.set_language(available_languages[language]) utils.use_database_for_world_cities(use_world_city_database) self.resources = utils.resource_strings self._place_name = place_of_birth self._bhava_chart_type = chart_type self._calculation_type = calculation_type self._show_compatibility = show_marriage_compatibility - ' read world cities' - #self._df = utils._world_city_db_df - #self._world_cities_db = utils.world_cities_db - self._conjunction_dialog_accepted = False; self._conj_planet1=''; self._conj_planet2=''; self._raasi='' - self._lunar_month_type = '' - self._separation_angle_list = [] - self._separation_angle_index = 0 + + self._conjunction_dialog_accepted = False + self._conj_planet1 = "" + self._conj_planet2 = "" + self._raasi = "" + self._lunar_month_type = "" + self._separation_angle_list: list = [] + self._separation_angle_index = 0 + + def _build_ui(self) -> None: + """Construct all UI widgets.""" + self._init_main_window() self._v_layout = QVBoxLayout() self._create_row1_ui() @@ -308,24 +397,31 @@ def __init__(self,chart_type='south_indian',show_marriage_compatibility=True, ca if self._show_compatibility: self._create_comp_ui() self._init_tab_widget_ui() - current_date_str,current_time_str = datetime.now().strftime('%Y,%m,%d;%H:%M:%S').split(';') - if date_of_birth == None: + + def _populate_defaults(self, date_of_birth: str | None, time_of_birth: str | None, gender: int) -> None: + """Populate initial values and compute julian day.""" + + current_date_str, current_time_str = datetime.now().strftime("%Y,%m,%d;%H:%M:%S").split(";") + if date_of_birth is None: self.date_of_birth(current_date_str) - if time_of_birth == None: + if time_of_birth is None: self.time_of_birth(current_time_str) + if not self._validate_ui() and self.use_internet_for_location_check: loc = utils.get_place_from_user_ip_address() - print('loc from IP address',loc) - if len(loc)==4: - print('setting values from loc') - self.place(loc[0],loc[1],loc[2],loc[3]) - if gender==None or gender not in [0,1,2,3]: self.gender(0) - year,month,day = self._dob_text.text().split(",") - dob = (int(year),int(month),int(day)) - tob = tuple([int(x) for x in self._tob_text.text().split(':')]) + if len(loc) == 4: + self.place(loc[0], loc[1], loc[2], loc[3]) + + if gender is None or gender not in [0, 1, 2, 3]: + self.gender(0) + else: + self.gender(gender) + + year, month, day = self._dob_text.text().split(",") + dob = (int(year), int(month), int(day)) + tob = tuple(int(x) for x in self._tob_text.text().split(":")) self._birth_julian_day = utils.julian_day_number(dob, tob) - """ Commented in V4.0.4 to force explicit calling """ - #self.compute_horoscope(calculation_type=self._calculation_type) + def _hide_2nd_row_widgets(self,show=True): self._dob_label.setVisible(show) self._dob_text.setVisible(show) @@ -5616,7 +5712,7 @@ def except_hook(cls, exception, traceback): sys.excepthook = except_hook App = QApplication(sys.argv) chart = ChartTabbed() - chart.language('Tamil') + chart.language('English') """ chart.name('XXX')#'('Rama') chart.gender(1) #(0) diff --git a/src/pyside_app/__init__.py b/src/pyside_app/__init__.py new file mode 100644 index 0000000..2a5661f --- /dev/null +++ b/src/pyside_app/__init__.py @@ -0,0 +1 @@ +"""PySide6 desktop application for AstroCal.""" diff --git a/src/pyside_app/main.py b/src/pyside_app/main.py new file mode 100644 index 0000000..b8737a3 --- /dev/null +++ b/src/pyside_app/main.py @@ -0,0 +1,105 @@ +"""PySide6 based user interface for AstroCal. + +This module defines a simple Qt6 application using PySide6. +It demonstrates how to build scalable layouts with support +for high-DPI displays and a dark theme. Backend calculation +logic should be imported from other modules in the package. +""" + +from __future__ import annotations + +import sys + +from PySide6.QtCore import Qt, QCoreApplication +from PySide6.QtWidgets import ( + QApplication, + QLabel, + QMainWindow, + QTabWidget, + QTextEdit, + QVBoxLayout, + QWidget, +) + + +def init_high_dpi() -> None: + """Enable Qt high DPI attributes for 4K monitor support.""" + QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) + QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) + + +class MainWindow(QMainWindow): + """Main application window with tabbed interface.""" + + def __init__(self) -> None: + super().__init__() + self.setWindowTitle("AstroCal - PySide6") + # Default window size, still resizable + self.resize(1200, 800) + + # Apply global dark theme stylesheet and font size + self.setStyleSheet( + """ + QWidget { background-color: #121212; color: #dddddd; font-size: 16px; } + QTabWidget::pane { border: 1px solid #444444; } + QTabBar::tab { background: #333333; padding: 8px; } + QTabBar::tab:selected { background: #555555; } + """ + ) + + + self._init_ui() + + def _init_ui(self) -> None: + """Builds the tabbed user interface.""" + tabs = QTabWidget() + tabs.addTab(self._create_chart_tab(), "Chart Data") + tabs.addTab(self._create_bhava_tab(), "Bhava") + tabs.addTab(self._create_pakshi_tab(), "Panchapakshi") + tabs.addTab(self._create_calendar_tab(), "Calendar") + self.setCentralWidget(tabs) + + def _create_chart_tab(self) -> QWidget: + """First tab displaying placeholder chart data.""" + tab = QWidget() + layout = QVBoxLayout(tab) + + placeholder = QLabel("Chart Data Appears Here") + placeholder.setAlignment(Qt.AlignCenter) + layout.addWidget(placeholder) + + example = QTextEdit() + example.setPlainText("Example chart data...\n") + layout.addWidget(example) + return tab + + def _create_bhava_tab(self) -> QWidget: + tab = QWidget() + layout = QVBoxLayout(tab) + layout.addWidget(QLabel("Bhava details will appear here")) + return tab + + def _create_pakshi_tab(self) -> QWidget: + tab = QWidget() + layout = QVBoxLayout(tab) + layout.addWidget(QLabel("Panchapakshi information goes here")) + return tab + + def _create_calendar_tab(self) -> QWidget: + tab = QWidget() + layout = QVBoxLayout(tab) + layout.addWidget(QLabel("Calendar view will be placed here")) + return tab + + +def main(argv: list[str] | None = None) -> int: + """Entry point for the PySide6 application.""" + init_high_dpi() + app = QApplication(argv or sys.argv) + window = MainWindow() + window.show() + return app.exec() + + +if __name__ == "__main__": # pragma: no cover + raise SystemExit(main()) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..8c01c5b --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,17 @@ +import os +import sys +import pytest +from PySide6.QtWidgets import QApplication +from PySide6.QtCore import Qt, QCoreApplication + +@pytest.fixture(scope="session") +def qapp(): + """Create a QApplication instance for tests.""" + os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") + # Enable high DPI attributes before QApplication is created + QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) + QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) + app = QApplication.instance() or QApplication(sys.argv) + yield app + # Teardown - quit application to release resources + app.quit() diff --git a/tests/test_pyside_app.py b/tests/test_pyside_app.py new file mode 100644 index 0000000..bb7c733 --- /dev/null +++ b/tests/test_pyside_app.py @@ -0,0 +1,11 @@ +from pyside_app.main import MainWindow +from PySide6.QtWidgets import QTabWidget + + +def test_mainwindow_tabs(qapp): + window = MainWindow() + central = window.centralWidget() + assert isinstance(central, QTabWidget) + assert central.count() == 4 + titles = [central.tabText(i) for i in range(central.count())] + assert titles == ["Chart Data", "Bhava", "Panchapakshi", "Calendar"]