11from datetime import UTC , datetime , timedelta
2- from typing import Optional
2+ from typing import TypedDict
33
44from discord import Colour , Embed
55from discord .ext .commands import Cog , Context , command
6- from pydis_core .utils .caching import AsyncCache
76
87from bot .bot import Bot
98from bot .log import get_logger
1312ICON_URL = "https://www.python.org/static/opengraph-icon-200x200.png"
1413PEP_API_URL = "https://peps.python.org/api/peps.json"
1514
15+ class PEPInfo (TypedDict ):
16+ """
17+ Useful subset of the PEP API response.
18+
19+ Full structure documented at https://peps.python.org/api/
20+ """
21+
22+ number : int
23+ title : str
24+ url : str
25+ status : str
26+ python_version : str | None
27+ created : str
28+ type : str
29+
1630
1731class PythonEnhancementProposals (Cog ):
1832 """Cog for displaying information about PEPs."""
1933
2034 def __init__ (self , bot : Bot ):
2135 self .bot = bot
22- self .peps : dict [int , dict [ str , Optional [ str ]] ] = {}
23- self .last_refreshed_peps : Optional [ datetime ] = None
36+ self .peps : dict [int , PEPInfo ] = {}
37+ self .last_refreshed_peps : datetime | None = None
2438
2539 async def refresh_pep_data (self ) -> None :
2640 """Refresh PEP data."""
2741 # Putting this first should prevent any race conditions
2842 self .last_refreshed_peps = datetime .now (tz = UTC )
2943
30- # Wait until HTTP client is available
31- await self .bot .wait_until_ready ()
32-
3344 log .trace ("Started refreshing PEP data." )
3445 async with self .bot .http_session .get (PEP_API_URL ) as resp :
3546 if resp .status != 200 :
@@ -44,11 +55,10 @@ async def refresh_pep_data(self) -> None:
4455
4556 log .info ("Successfully refreshed PEP data." )
4657
47- def generate_pep_embed (self , pep_number : int ) -> Embed :
58+ def generate_pep_embed (self , pep : PEPInfo ) -> Embed :
4859 """Generate PEP embed."""
49- pep = self .peps [pep_number ]
5060 embed = Embed (
51- title = f"**PEP { pep_number } - { pep ['title' ]} **" ,
61+ title = f"**PEP { pep [ 'number' ] } - { pep ['title' ]} **" ,
5262 description = f"[Link]({ pep ['url' ]} )" ,
5363 )
5464 embed .set_thumbnail (url = ICON_URL )
@@ -64,24 +74,24 @@ def generate_pep_embed(self, pep_number: int) -> Embed:
6474 @command (name = "pep" , aliases = ("get_pep" , "p" ))
6575 async def pep_command (self , ctx : Context , pep_number : int ) -> None :
6676 """Fetches information about a PEP and sends it to the channel."""
77+ # Refresh the PEP data up to every hour, as e.g. the PEP status might have changed.
6778 if (
6879 self .last_refreshed_peps is None or (
69- pep_number not in self .peps
70- and (self .last_refreshed_peps + timedelta (minutes = 30 )) <= datetime .now ()
80+ (self .last_refreshed_peps + timedelta (hours = 1 )) <= datetime .now (tz = UTC )
7181 and len (str (pep_number )) < 5
7282 )
7383 ):
7484 await self .refresh_pep_data ()
7585
76- if pep_number not in self .peps :
86+ if pep := self .peps .get (pep_number ):
87+ embed = self .generate_pep_embed (pep )
88+ else :
7789 log .trace (f"PEP { pep_number } was not found" )
7890 embed = Embed (
7991 title = "PEP not found" ,
8092 description = f"PEP { pep_number } does not exist." ,
8193 colour = Colour .red (),
8294 )
83- else :
84- embed = self .generate_pep_embed (pep_number )
8595
8696 await ctx .send (embed = embed )
8797
0 commit comments