rosary 1.0.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.
rosary-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.3
2
+ Name: rosary
3
+ Version: 1.0.0
4
+ Summary: A terminal UI to guide users through the Rosary
5
+ Requires-Dist: textual>=0.74
6
+ Requires-Dist: httpx>=0.27
7
+ Requires-Python: >=3.13
8
+ Description-Content-Type: text/markdown
9
+
10
+ # rosary
11
+
12
+ `rosary` is a terminal application for praying the Holy Rosary step by step. It guides you through the opening prayers, the five decades, and the closing prayers in a clean Textual interface, with mystery descriptions and scripture references included along the way.
13
+
14
+ ## Features
15
+
16
+ - Guided Rosary flow from beginning to end
17
+ - English and Latin prayer modes
18
+ - Bible translation selection in English mode
19
+ - Automatic mystery recommendation based on the day of the week
20
+ - Intentions prompt before the Rosary begins
21
+ - Scripture lookups for mysteries with direct biblical references
22
+ - Built-in fallback translation list if the live API is unavailable
23
+
24
+ ## Requirements
25
+
26
+ - Python 3.13 or newer
27
+ - A terminal that supports Textual applications
28
+ - Internet access for live translation and scripture fetching
29
+
30
+ ## Installation
31
+
32
+ ### From PyPI
33
+
34
+ ```bash
35
+ pip install rosary
36
+ ```
37
+
38
+ If you prefer an isolated CLI install:
39
+
40
+ ```bash
41
+ pipx install rosary
42
+ ```
43
+
44
+ ## Quick start
45
+
46
+ Run the app with:
47
+
48
+ ```bash
49
+ rosary
50
+ ```
51
+
52
+ You will then:
53
+
54
+ 1. Choose **English** or **Latin**.
55
+ 2. Select a Bible translation in English mode.
56
+ 3. Accept the suggested mystery set for the day or choose another one.
57
+ 4. Offer your intentions.
58
+ 5. Move through the Rosary one step at a time.
59
+
60
+ ## Mystery schedule
61
+
62
+ The app suggests the traditional mystery set for the current weekday:
63
+
64
+ | Day | Mysteries |
65
+ | --- | --- |
66
+ | Monday | Joyful |
67
+ | Tuesday | Sorrowful |
68
+ | Wednesday | Glorious |
69
+ | Thursday | Luminous |
70
+ | Friday | Sorrowful |
71
+ | Saturday | Joyful |
72
+ | Sunday | Glorious |
73
+
74
+ You can always override the suggestion from the selection screen.
75
+
76
+ ## Keyboard controls
77
+
78
+ ### Selection screens
79
+
80
+ - `q` to quit
81
+ - `escape` to go back when available
82
+ - arrow keys to move through options
83
+ - `enter` to confirm a selection
84
+
85
+ ### Rosary screen
86
+
87
+ - `space` or `right arrow` for the next step
88
+ - `backspace` or `left arrow` for the previous step
89
+ - `q` to quit
90
+ - `r` to start again after completion
91
+
92
+ ## Included prayer flow
93
+
94
+ The guided flow includes:
95
+
96
+ - Sign of the Cross
97
+ - Apostles' Creed
98
+ - Our Father
99
+ - three Hail Marys
100
+ - Glory Be
101
+ - five decades with mystery descriptions
102
+ - Hail Holy Queen
103
+ - Closing Prayer
104
+ - Sign of the Cross
105
+
106
+ For mysteries such as the Assumption and Coronation, the app shows a doctrinal note when no direct scripture passage is used.
107
+
108
+ ## Development
109
+
110
+ To work on the project locally:
111
+
112
+ ```bash
113
+ python -m venv .venv
114
+ source .venv/bin/activate
115
+ pip install -e .
116
+ ```
117
+
118
+ Or with `uv`:
119
+
120
+ ```bash
121
+ uv sync
122
+ uv run rosary
123
+ ```
124
+
125
+ ## Project layout
126
+
127
+ ```text
128
+ src/rosary/
129
+ ├── api.py # bible-api.com client
130
+ ├── app.py # top-level Textual app
131
+ ├── main.py # CLI entry point
132
+ ├── mysteries.py # mystery definitions and weekday suggestion logic
133
+ ├── prayers.py # English and Latin prayer texts
134
+ └── screens/
135
+ ├── welcome.py
136
+ ├── mystery_select.py
137
+ ├── intentions.py
138
+ └── rosary.py
139
+ ```
140
+
141
+ ## License
142
+
143
+ See `LICENSE`.
rosary-1.0.0/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # rosary
2
+
3
+ `rosary` is a terminal application for praying the Holy Rosary step by step. It guides you through the opening prayers, the five decades, and the closing prayers in a clean Textual interface, with mystery descriptions and scripture references included along the way.
4
+
5
+ ## Features
6
+
7
+ - Guided Rosary flow from beginning to end
8
+ - English and Latin prayer modes
9
+ - Bible translation selection in English mode
10
+ - Automatic mystery recommendation based on the day of the week
11
+ - Intentions prompt before the Rosary begins
12
+ - Scripture lookups for mysteries with direct biblical references
13
+ - Built-in fallback translation list if the live API is unavailable
14
+
15
+ ## Requirements
16
+
17
+ - Python 3.13 or newer
18
+ - A terminal that supports Textual applications
19
+ - Internet access for live translation and scripture fetching
20
+
21
+ ## Installation
22
+
23
+ ### From PyPI
24
+
25
+ ```bash
26
+ pip install rosary
27
+ ```
28
+
29
+ If you prefer an isolated CLI install:
30
+
31
+ ```bash
32
+ pipx install rosary
33
+ ```
34
+
35
+ ## Quick start
36
+
37
+ Run the app with:
38
+
39
+ ```bash
40
+ rosary
41
+ ```
42
+
43
+ You will then:
44
+
45
+ 1. Choose **English** or **Latin**.
46
+ 2. Select a Bible translation in English mode.
47
+ 3. Accept the suggested mystery set for the day or choose another one.
48
+ 4. Offer your intentions.
49
+ 5. Move through the Rosary one step at a time.
50
+
51
+ ## Mystery schedule
52
+
53
+ The app suggests the traditional mystery set for the current weekday:
54
+
55
+ | Day | Mysteries |
56
+ | --- | --- |
57
+ | Monday | Joyful |
58
+ | Tuesday | Sorrowful |
59
+ | Wednesday | Glorious |
60
+ | Thursday | Luminous |
61
+ | Friday | Sorrowful |
62
+ | Saturday | Joyful |
63
+ | Sunday | Glorious |
64
+
65
+ You can always override the suggestion from the selection screen.
66
+
67
+ ## Keyboard controls
68
+
69
+ ### Selection screens
70
+
71
+ - `q` to quit
72
+ - `escape` to go back when available
73
+ - arrow keys to move through options
74
+ - `enter` to confirm a selection
75
+
76
+ ### Rosary screen
77
+
78
+ - `space` or `right arrow` for the next step
79
+ - `backspace` or `left arrow` for the previous step
80
+ - `q` to quit
81
+ - `r` to start again after completion
82
+
83
+ ## Included prayer flow
84
+
85
+ The guided flow includes:
86
+
87
+ - Sign of the Cross
88
+ - Apostles' Creed
89
+ - Our Father
90
+ - three Hail Marys
91
+ - Glory Be
92
+ - five decades with mystery descriptions
93
+ - Hail Holy Queen
94
+ - Closing Prayer
95
+ - Sign of the Cross
96
+
97
+ For mysteries such as the Assumption and Coronation, the app shows a doctrinal note when no direct scripture passage is used.
98
+
99
+ ## Development
100
+
101
+ To work on the project locally:
102
+
103
+ ```bash
104
+ python -m venv .venv
105
+ source .venv/bin/activate
106
+ pip install -e .
107
+ ```
108
+
109
+ Or with `uv`:
110
+
111
+ ```bash
112
+ uv sync
113
+ uv run rosary
114
+ ```
115
+
116
+ ## Project layout
117
+
118
+ ```text
119
+ src/rosary/
120
+ ├── api.py # bible-api.com client
121
+ ├── app.py # top-level Textual app
122
+ ├── main.py # CLI entry point
123
+ ├── mysteries.py # mystery definitions and weekday suggestion logic
124
+ ├── prayers.py # English and Latin prayer texts
125
+ └── screens/
126
+ ├── welcome.py
127
+ ├── mystery_select.py
128
+ ├── intentions.py
129
+ └── rosary.py
130
+ ```
131
+
132
+ ## License
133
+
134
+ See `LICENSE`.
@@ -0,0 +1,28 @@
1
+ [project]
2
+ name = "rosary"
3
+ version = "1.0.0"
4
+ description = "A terminal UI to guide users through the Rosary"
5
+ readme = "README.md"
6
+ requires-python = ">=3.13"
7
+ dependencies = [
8
+ "textual>=0.74",
9
+ "httpx>=0.27",
10
+ ]
11
+
12
+ [project.scripts]
13
+ rosary = "rosary.main:main"
14
+ release = "scripts.release:main"
15
+
16
+ [build-system]
17
+ requires = ["uv_build>=0.11.3,<0.12"]
18
+ build-backend = "uv_build"
19
+
20
+ [tool.pytest.ini_options]
21
+ asyncio_mode = "auto"
22
+
23
+ [dependency-groups]
24
+ dev = [
25
+ "pytest>=9.0.2",
26
+ "pytest-asyncio>=1.3.0",
27
+ "respx>=0.22.0",
28
+ ]
File without changes
@@ -0,0 +1,96 @@
1
+ """Async client for bible-api.com."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import httpx
6
+
7
+ BASE_URL = "https://bible-api.com"
8
+
9
+ # Translations available on bible-api.com (identifier → display name).
10
+ # This is fetched live; this list is kept as a static fallback.
11
+ _FALLBACK_TRANSLATIONS: list[dict] = [
12
+ {"identifier": "web", "name": "World English Bible", "language": "English"},
13
+ {"identifier": "kjv", "name": "King James Version", "language": "English"},
14
+ {
15
+ "identifier": "asv",
16
+ "name": "American Standard Version (1901)",
17
+ "language": "English",
18
+ },
19
+ {"identifier": "bbe", "name": "Bible in Basic English", "language": "English"},
20
+ {"identifier": "darby", "name": "Darby Bible", "language": "English"},
21
+ {
22
+ "identifier": "dra",
23
+ "name": "Douay-Rheims 1899 American Edition",
24
+ "language": "English",
25
+ },
26
+ {"identifier": "ylt", "name": "Young's Literal Translation", "language": "English"},
27
+ {
28
+ "identifier": "oeb-cw",
29
+ "name": "Open English Bible, Commonwealth Edition",
30
+ "language": "English (UK)",
31
+ },
32
+ {
33
+ "identifier": "oeb-us",
34
+ "name": "Open English Bible, US Edition",
35
+ "language": "English (US)",
36
+ },
37
+ {
38
+ "identifier": "webbe",
39
+ "name": "World English Bible, British Edition",
40
+ "language": "English (UK)",
41
+ },
42
+ {
43
+ "identifier": "clementine",
44
+ "name": "Clementine Latin Vulgate",
45
+ "language": "Latin",
46
+ },
47
+ {
48
+ "identifier": "almeida",
49
+ "name": "João Ferreira de Almeida",
50
+ "language": "Portuguese",
51
+ },
52
+ {
53
+ "identifier": "rccv",
54
+ "name": "Protestant Romanian Cornilescu Version",
55
+ "language": "Romanian",
56
+ },
57
+ {"identifier": "cuv", "name": "Chinese Union Version", "language": "Chinese"},
58
+ {"identifier": "bkr", "name": "Bible kralická", "language": "Czech"},
59
+ {
60
+ "identifier": "cherokee",
61
+ "name": "Cherokee New Testament",
62
+ "language": "Cherokee",
63
+ },
64
+ ]
65
+
66
+
67
+ async def fetch_translations() -> tuple[list[dict], bool]:
68
+ """Return (translations, api_error).
69
+
70
+ translations: list of dicts with keys identifier, name, language.
71
+ api_error: True if the live API could not be reached (fallback used).
72
+ """
73
+ async with httpx.AsyncClient(timeout=10.0) as client:
74
+ try:
75
+ response = await client.get(f"{BASE_URL}/data")
76
+ response.raise_for_status()
77
+ data = response.json()
78
+ return data.get("translations", _FALLBACK_TRANSLATIONS), False
79
+ except (httpx.HTTPError, KeyError, ValueError):
80
+ return _FALLBACK_TRANSLATIONS, True
81
+
82
+
83
+ async def fetch_verse(ref: str, translation_id: str) -> str:
84
+ """Fetch the text for a scripture reference.
85
+
86
+ Returns the combined verse text, or an empty string on failure.
87
+ """
88
+ url = f"{BASE_URL}/{ref}"
89
+ async with httpx.AsyncClient(timeout=10.0) as client:
90
+ try:
91
+ response = await client.get(url, params={"translation": translation_id})
92
+ response.raise_for_status()
93
+ data = response.json()
94
+ return data.get("text", "").strip()
95
+ except (httpx.HTTPError, KeyError, ValueError):
96
+ return ""
@@ -0,0 +1,28 @@
1
+ """RosaryApp — top-level Textual application."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from textual.app import App
6
+
7
+ from rosary.screens.welcome import WelcomeScreen
8
+
9
+
10
+ class RosaryApp(App):
11
+ """A TUI guide through the Holy Rosary."""
12
+
13
+ TITLE = "The Holy Rosary"
14
+ CSS = """
15
+ App {
16
+ background: $surface;
17
+ }
18
+ """
19
+
20
+ # Shared state written by WelcomeScreen / MysterySelectScreen,
21
+ # read by RosaryScreen.
22
+ translation_id: str = "kjv"
23
+ translation_name: str = "King James Version"
24
+ mystery_set_key: str = "Joyful"
25
+ language: str = "English"
26
+
27
+ def on_mount(self) -> None:
28
+ self.push_screen(WelcomeScreen())
@@ -0,0 +1,9 @@
1
+ from rosary.app import RosaryApp
2
+
3
+
4
+ def main() -> None:
5
+ RosaryApp().run()
6
+
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1,179 @@
1
+ """Rosary mystery sets and day-of-week suggestion logic."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from datetime import date
7
+ from typing import Optional
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class Mystery:
12
+ name: str
13
+ description: str
14
+ scripture_ref: Optional[str] # None when no direct scriptural citation exists
15
+ scripture_note: Optional[str] = None # displayed in place of a verse
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class MysterySet:
20
+ name: str
21
+ mysteries: tuple[Mystery, ...]
22
+
23
+
24
+ JOYFUL = MysterySet(
25
+ name="Joyful Mysteries",
26
+ mysteries=(
27
+ Mystery(
28
+ name="The Annunciation",
29
+ description="The Angel Gabriel announces to Mary that she will conceive the Son of God.",
30
+ scripture_ref="Luke 1:26-33",
31
+ ),
32
+ Mystery(
33
+ name="The Visitation",
34
+ description="Mary visits her cousin Elizabeth, who is carrying John the Baptist.",
35
+ scripture_ref="Luke 1:39-45",
36
+ ),
37
+ Mystery(
38
+ name="The Nativity",
39
+ description="Jesus is born in Bethlehem.",
40
+ scripture_ref="Luke 2:6-12",
41
+ ),
42
+ Mystery(
43
+ name="The Presentation",
44
+ description="Mary and Joseph present Jesus in the Temple.",
45
+ scripture_ref="Luke 2:22-24",
46
+ ),
47
+ Mystery(
48
+ name="The Finding in the Temple",
49
+ description="The young Jesus is found teaching in the Temple after being lost for three days.",
50
+ scripture_ref="Luke 2:46-49",
51
+ ),
52
+ ),
53
+ )
54
+
55
+ SORROWFUL = MysterySet(
56
+ name="Sorrowful Mysteries",
57
+ mysteries=(
58
+ Mystery(
59
+ name="The Agony in the Garden",
60
+ description="Jesus prays in the Garden of Gethsemane, sweating blood before his Passion.",
61
+ scripture_ref="Luke 22:41-44",
62
+ ),
63
+ Mystery(
64
+ name="The Scourging at the Pillar",
65
+ description="Jesus is bound and brutally scourged by Roman soldiers.",
66
+ scripture_ref="John 19:1",
67
+ ),
68
+ Mystery(
69
+ name="The Crowning with Thorns",
70
+ description="The soldiers place a crown of thorns on Jesus and mock him as king.",
71
+ scripture_ref="John 19:2-3",
72
+ ),
73
+ Mystery(
74
+ name="The Carrying of the Cross",
75
+ description="Jesus carries his cross to Calvary, falling under its weight.",
76
+ scripture_ref="John 19:17",
77
+ ),
78
+ Mystery(
79
+ name="The Crucifixion",
80
+ description="Jesus is nailed to the cross and dies for the sins of all humanity.",
81
+ scripture_ref="John 19:28-30",
82
+ ),
83
+ ),
84
+ )
85
+
86
+ GLORIOUS = MysterySet(
87
+ name="Glorious Mysteries",
88
+ mysteries=(
89
+ Mystery(
90
+ name="The Resurrection",
91
+ description="Jesus rises from the dead on the third day.",
92
+ scripture_ref="John 20:1-2",
93
+ ),
94
+ Mystery(
95
+ name="The Ascension",
96
+ description="Jesus ascends into heaven forty days after the Resurrection.",
97
+ scripture_ref="Acts 1:9-11",
98
+ ),
99
+ Mystery(
100
+ name="The Descent of the Holy Spirit",
101
+ description="The Holy Spirit descends on the Apostles at Pentecost.",
102
+ scripture_ref="Acts 2:1-4",
103
+ ),
104
+ Mystery(
105
+ name="The Assumption of Mary",
106
+ description="At the end of her earthly life, Mary is taken body and soul into heaven.",
107
+ scripture_ref=None,
108
+ scripture_note=(
109
+ "The Assumption is a defined dogma of the Church (Munificentissimus Deus, 1950) "
110
+ "rather than a direct scriptural event. Revelation 12 is understood by many "
111
+ "as a typological reference to Mary."
112
+ ),
113
+ ),
114
+ Mystery(
115
+ name="The Coronation of Mary",
116
+ description="Mary is crowned Queen of Heaven and Earth.",
117
+ scripture_ref=None,
118
+ scripture_note=(
119
+ "The Coronation is a defined dogma of the Church rooted in Sacred Tradition. "
120
+ 'Revelation 12:1 — "A great sign appeared in heaven: a woman clothed with '
121
+ 'the sun, with the moon under her feet and a crown of twelve stars on her head."'
122
+ ),
123
+ ),
124
+ ),
125
+ )
126
+
127
+ LUMINOUS = MysterySet(
128
+ name="Luminous Mysteries",
129
+ mysteries=(
130
+ Mystery(
131
+ name="The Baptism of Jesus",
132
+ description="Jesus is baptized by John in the Jordan, and the Holy Spirit descends as a dove.",
133
+ scripture_ref="Matthew 3:16-17",
134
+ ),
135
+ Mystery(
136
+ name="The Wedding at Cana",
137
+ description="At Mary's intercession, Jesus performs his first miracle — water into wine.",
138
+ scripture_ref="John 2:3-5",
139
+ ),
140
+ Mystery(
141
+ name="The Proclamation of the Kingdom",
142
+ description="Jesus preaches repentance and the coming of the Kingdom of God.",
143
+ scripture_ref="Mark 1:14-15",
144
+ ),
145
+ Mystery(
146
+ name="The Transfiguration",
147
+ description="Jesus is transfigured on Mount Tabor, revealing his divine glory.",
148
+ scripture_ref="Matthew 17:1-2",
149
+ ),
150
+ Mystery(
151
+ name="The Institution of the Eucharist",
152
+ description="At the Last Supper, Jesus institutes the Eucharist.",
153
+ scripture_ref="Luke 22:19-20",
154
+ ),
155
+ ),
156
+ )
157
+
158
+ ALL_SETS: dict[str, MysterySet] = {
159
+ "Joyful": JOYFUL,
160
+ "Sorrowful": SORROWFUL,
161
+ "Glorious": GLORIOUS,
162
+ "Luminous": LUMINOUS,
163
+ }
164
+
165
+ # Traditional day assignments (Luminous added by John Paul II for Thursday)
166
+ _DAY_TO_SET: dict[int, str] = {
167
+ 0: "Joyful", # Monday
168
+ 1: "Sorrowful", # Tuesday
169
+ 2: "Glorious", # Wednesday
170
+ 3: "Luminous", # Thursday
171
+ 4: "Sorrowful", # Friday
172
+ 5: "Joyful", # Saturday
173
+ 6: "Glorious", # Sunday
174
+ }
175
+
176
+
177
+ def suggest_mystery_set() -> str:
178
+ """Return the key for the traditionally suggested mystery set for today."""
179
+ return _DAY_TO_SET[date.today().weekday()]