Skip to content

Commit 073589a

Browse files
committed
✨ Add a cache facility to the PEP source viewer screen
1 parent 1b8f02c commit 073589a

File tree

1 file changed

+54
-17
lines changed

1 file changed

+54
-17
lines changed

src/peplum/app/screens/pep_viewer.py

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
"""A dialog for viewing the text of a PEP."""
22

3+
##############################################################################
4+
# Python imports.
5+
from pathlib import Path
6+
37
##############################################################################
48
# Textual imports.
59
from textual import on, work
@@ -11,7 +15,7 @@
1115
##############################################################################
1216
# Local imports.
1317
from ...peps import API
14-
from ..data import PEP
18+
from ..data import PEP, cache_dir
1519

1620

1721
##############################################################################
@@ -57,7 +61,7 @@ class PEPViewer(ModalScreen[None]):
5761
}
5862
"""
5963

60-
BINDINGS = [("escape", "close")]
64+
BINDINGS = [("escape", "close"), ("ctrl+r", "refresh")]
6165

6266
def __init__(self, pep: PEP) -> None:
6367
"""Initialise the dialog.
@@ -75,34 +79,67 @@ def compose(self) -> ComposeResult:
7579
dialog.border_title = f"PEP{self._pep.number}"
7680
yield VerticalScroll(Static(id="text"), id="viewer")
7781
with Horizontal(id="buttons"):
78-
yield Button("Close [dim]\\[Esc][/]", variant="default")
82+
yield Button("Refresh [dim]\\[^r][/]", id="refresh")
83+
yield Button("Close [dim]\\[Esc][/]", id="close")
84+
85+
@property
86+
def _cache_name(self) -> Path:
87+
"""The name of the file that is the cached version of the PEP source."""
88+
return cache_dir() / API.pep_file(self._pep.number)
7989

8090
@work
8191
async def _download_text(self) -> None:
82-
"""Download the text of the PEP."""
83-
try:
84-
self.query_one("#text", Static).update(
85-
await API().get_pep(self._pep.number)
86-
)
87-
except API.RequestError as error:
88-
self.query_one("#text", Static).update("[error]Error[/]")
89-
self.notify(
90-
str(error), title="Error downloading PEP source", severity="error"
91-
)
92-
return
93-
finally:
94-
self.query_one("#viewer").loading = False
92+
"""Download the text of the PEP.
93+
94+
Notes:
95+
Once downloaded a local copy will be saved. Subsequently, when
96+
attempting to download the PEP, this local copy will be used
97+
instead.
98+
"""
99+
pep_source = ""
100+
if self._cache_name.exists():
101+
try:
102+
pep_source = self._cache_name.read_text(encoding="utf-8")
103+
except IOError:
104+
pass
105+
106+
if not pep_source:
107+
try:
108+
self._cache_name.write_text(
109+
pep_source := await API().get_pep(self._pep.number),
110+
encoding="utf-8",
111+
)
112+
except IOError:
113+
pass
114+
except API.RequestError as error:
115+
pep_source = "Error downloading PEP source"
116+
self.notify(
117+
str(error), title="Error downloading PEP source", severity="error"
118+
)
119+
120+
self.query_one("#text", Static).update(pep_source)
121+
self.query_one("#viewer").loading = False
95122
self.set_focus(self.query_one("#viewer"))
96123

97124
def on_mount(self) -> None:
98125
"""Populate the dialog once the"""
99126
self.query_one("#viewer").loading = True
100127
self._download_text()
101128

102-
@on(Button.Pressed)
129+
@on(Button.Pressed, "#close")
103130
def action_close(self) -> None:
104131
"""Close the dialog."""
105132
self.dismiss(None)
106133

134+
@on(Button.Pressed, "#refresh")
135+
def action_refresh(self) -> None:
136+
"""Refresh the PEP source."""
137+
try:
138+
self._cache_name.unlink(missing_ok=True)
139+
except IOError:
140+
pass
141+
self.query_one("#viewer").loading = True
142+
self._download_text()
143+
107144

108145
### pep_viewer.py ends here

0 commit comments

Comments
 (0)