Skip to content

Commit f814685

Browse files
JacobCoffeeAlc-AlcAlc-Alc
authored
feat: add python pep embeds (#71)
* feat: add python pep embeds * Update src/byte/lib/utils.py * chore: clean up commons imports * feat: ``ExtendedEmbed`` with convenience methods (#72) feat: `ExtendedEmbed` and some convenience methods Co-authored-by: Alc-Alc <alc@localhost> * chore: 404 no pep found made ephemeral * feat: finalize pep embed format --------- Co-authored-by: Alc-Alc <[email protected]> Co-authored-by: Alc-Alc <alc@localhost>
1 parent ac921c9 commit f814685

File tree

19 files changed

+523
-131
lines changed

19 files changed

+523
-131
lines changed

pdm.lock

Lines changed: 22 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,10 @@ exclude = [
157157
pythonVersion = "3.11"
158158
reportOptionalMemberAccess = false
159159
reportUnknownMemberType = false
160-
reportGeneralTypeIssues = false
160+
reportGeneralTypeIssues = true
161161

162162
[tool.mypy]
163-
namespace_packages = true # discord.py
163+
namespace_packages = true # discord.Githupy
164164
disallow_any_generics = false
165165
disallow_incomplete_defs = true
166166
disallow_untyped_decorators = false

src/byte/lib/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Byte library module."""
22

3-
from byte.lib import settings, utils
3+
from byte.lib import common, log, settings, utils
44

55
__all__ = [
66
"settings",
77
"utils",
8+
"log",
9+
"common",
810
]

src/byte/lib/common/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""Common variables and functions for use throughout Byte.
2+
3+
.. todo:: temporary, these are not multi-guild friendly.
4+
"""
5+
6+
from byte.lib.common import assets, colors, guilds, links
7+
8+
__all__ = (
9+
"assets",
10+
"colors",
11+
"guilds",
12+
"links",
13+
)

src/byte/lib/common/assets.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""Common variables and functions for use throughout Byte.
2+
3+
.. todo:: temporary, these are not multi-guild friendly.
4+
"""
5+
from typing import Final
6+
7+
# --- Assets
8+
litestar_logo_white: Final = "https://raw.githubusercontent.com/litestar-org/branding/main/assets/Branding%20-%20PNG%20-%20Transparent/Badge%20-%20White.png"
9+
litestar_logo_yellow: Final = "https://raw.githubusercontent.com/litestar-org/branding/main/assets/Branding%20-%20PNG%20-%20Transparent/Badge%20-%20Blue%20and%20Yellow.png"
10+
ruff_logo: Final = "https://raw.githubusercontent.com/JacobCoffee/byte/main/assets/ruff.png"
11+
python_logo: Final = "https://raw.githubusercontent.com/JacobCoffee/byte/main/assets/python.png"

src/byte/lib/common/colors.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""Common variables and functions for use throughout Byte.
2+
3+
.. todo:: temporary, these are not multi-guild friendly.
4+
"""
5+
from typing import Final
6+
7+
# --- Colors
8+
litestar_blue: Final = 0x7289DA
9+
python_blue: Final = 0x4B8BBE
10+
python_yellow: Final = 0xFFD43B
11+
astral_yellow: Final = 0xD7FF64
12+
astral_purple: Final = 0x261230

src/byte/lib/common/guilds.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"""Common variables and functions for use throughout Byte.
2+
3+
.. todo:: temporary, these are not multi-guild friendly.
4+
"""
5+
from typing import Final
6+
7+
# --- Channel IDs
8+
litestar_help_channel: Final = 1064114019373432912
Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,3 @@
1313
mcve: Final = "https://stackoverflow.com/help/minimal-reproducible-example"
1414
pastebin: Final = "https://paste.pythondiscord.com"
1515
markdown_guide: Final = "https://support.discord.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-Formatting-Bold-Italic-Underline-#h_01GY0DAKGXDEHE263BCAYEGFJA"
16-
17-
# --- Assets
18-
litestar_logo_white: Final = "https://raw.githubusercontent.com/litestar-org/branding/main/assets/Branding%20-%20PNG%20-%20Transparent/Badge%20-%20White.png"
19-
litestar_logo_yellow: Final = "https://raw.githubusercontent.com/litestar-org/branding/main/assets/Branding%20-%20PNG%20-%20Transparent/Badge%20-%20Blue%20and%20Yellow.png"
20-
ruff_logo: Final = "https://raw.githubusercontent.com/JacobCoffee/byte/main/assets/ruff.png"
21-
22-
# --- Channel IDs
23-
litestar_help_channel: Final = 1064114019373432912

src/byte/lib/utils.py

Lines changed: 149 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import json
55
import re
66
import subprocess
7+
from datetime import UTC, datetime
8+
from enum import StrEnum
79
from itertools import islice
810
from typing import TYPE_CHECKING, TypedDict, TypeVar
911

@@ -13,7 +15,7 @@
1315
from ruff.__main__ import find_ruff_bin # type: ignore[import-untyped]
1416

1517
from byte.lib import settings
16-
from byte.lib.common import pastebin
18+
from byte.lib.common.links import pastebin
1719

1820
if TYPE_CHECKING:
1921
from collections.abc import Iterable
@@ -22,45 +24,122 @@
2224
from discord.ext.commands import Context
2325
from discord.ext.commands._types import Check
2426

27+
__all__ = (
28+
"BaseRuffRule",
29+
"RuffRule",
30+
"FormattedRuffRule",
31+
"PEP",
32+
"is_byte_dev",
33+
"linker",
34+
"mention_user",
35+
"mention_user_nickname",
36+
"mention_channel",
37+
"mention_role",
38+
"mention_slash_command",
39+
"mention_custom_emoji",
40+
"mention_custom_emoji_animated",
41+
"mention_timestamp",
42+
"mention_guild_navigation",
43+
"format_ruff_rule",
44+
"query_all_ruff_rules",
45+
"run_ruff_format",
46+
"paste",
47+
"chunk_sequence",
48+
"query_all_peps",
49+
)
50+
2551
_T = TypeVar("_T")
2652

2753

2854
class BaseRuffRule(TypedDict):
55+
"""Base Ruff rule data."""
56+
2957
name: str
3058
summary: str
3159
fix: str
3260
explanation: str
3361

3462

3563
class RuffRule(BaseRuffRule):
64+
"""Ruff rule data."""
65+
3666
code: str
3767
linter: str
3868
message_formats: list[str]
3969
preview: bool
4070

4171

4272
class FormattedRuffRule(BaseRuffRule):
73+
"""Formatted Ruff rule data."""
74+
4375
rule_link: str
4476
rule_anchor_link: str
4577

4678

47-
__all__ = (
48-
"is_byte_dev",
49-
"linker",
50-
"mention_user",
51-
"mention_user_nickname",
52-
"mention_channel",
53-
"mention_role",
54-
"mention_slash_command",
55-
"mention_custom_emoji",
56-
"mention_custom_emoji_animated",
57-
"mention_timestamp",
58-
"mention_guild_navigation",
59-
"format_ruff_rule",
60-
"query_all_ruff_rules",
61-
"run_ruff_format",
62-
"paste",
63-
)
79+
class PEPType(StrEnum):
80+
"""Type of PEP.
81+
82+
Based off of `PEP Types in PEP1 <https://peps.python.org/#pep-types-key>`_.
83+
"""
84+
85+
I = "Informational" # noqa: E741
86+
P = "Process"
87+
S = "Standards Track"
88+
89+
90+
class PEPStatus(StrEnum):
91+
"""Status of a PEP.
92+
93+
.. note:: ``Active`` and ``Accepted`` both traditionally use ``A``,
94+
but are differentiated here for clarity.
95+
96+
Based off of `PEP Status in PEP1 <https://peps.python.org/#pep-status-key>`_.
97+
"""
98+
99+
A = "Active"
100+
AA = "Accepted"
101+
D = "Deferred"
102+
__ = "Draft"
103+
F = "Final"
104+
P = "Provisional"
105+
R = "Rejected"
106+
S = "Superseded"
107+
W = "Withdrawn"
108+
109+
110+
class PEPHistoryItem(TypedDict, total=False):
111+
"""PEP history item.
112+
113+
Sometimes these include a list of ``datetime`` objects,
114+
other times they are a list of datetime and str
115+
because they contain a date and an rST link.
116+
"""
117+
118+
date: str
119+
link: str
120+
121+
122+
class PEP(TypedDict):
123+
"""PEP data.
124+
125+
Based off of the `PEPS API <https://peps.python.org/api/peps.json>`_.
126+
"""
127+
128+
number: int
129+
title: str
130+
authors: list[str] | str
131+
discussions_to: str
132+
status: PEPStatus
133+
type: PEPType
134+
topic: str
135+
created: datetime
136+
python_version: list[float] | float
137+
post_history: list[str]
138+
resolution: str | None
139+
requires: str | None
140+
replaces: str | None
141+
superseded_by: str | None
142+
url: str
64143

65144

66145
def is_byte_dev() -> Check[Any]:
@@ -311,3 +390,55 @@ def chunk_sequence(sequence: Iterable[_T], size: int) -> Iterable[tuple[_T, ...]
311390
_sequence = iter(sequence)
312391
while chunk := tuple(islice(_sequence, size)):
313392
yield chunk
393+
394+
395+
def format_resolution_link(resolution: str | None) -> str:
396+
"""Formats the resolution URL into a markdown link.
397+
398+
Args:
399+
resolution (str): The resolution URL.
400+
401+
Returns:
402+
str: The formatted markdown link.
403+
"""
404+
if not resolution:
405+
return "N/A"
406+
if "discuss.python.org" in resolution:
407+
return f"[via Discussion Forum]({resolution})"
408+
if "mail.python.org" in resolution:
409+
return f"[via Mailist]({resolution})"
410+
return resolution
411+
412+
413+
async def query_all_peps() -> list[PEP]:
414+
"""Query all PEPs from the PEPs Python.org API.
415+
416+
Returns:
417+
list[PEP]: All PEPs
418+
"""
419+
url = "https://peps.python.org/api/peps.json"
420+
async with httpx.AsyncClient() as client:
421+
response = await client.get(url)
422+
response.raise_for_status()
423+
data = response.json()
424+
425+
return [ # type: ignore[reportReturnType]
426+
{
427+
"number": pep_info["number"],
428+
"title": pep_info["title"],
429+
"authors": pep_info["authors"].split(", "),
430+
"discussions_to": pep_info["discussions_to"],
431+
"status": PEPStatus(pep_info["status"]),
432+
"type": PEPType(pep_info["type"]),
433+
"topic": pep_info.get("topic", ""),
434+
"created": datetime.strptime(pep_info["created"], "%d-%b-%Y").replace(tzinfo=UTC).strftime("%Y-%m-%d"),
435+
"python_version": pep_info.get("python_version"),
436+
"post_history": pep_info.get("post_history", []),
437+
"resolution": format_resolution_link(pep_info.get("resolution", "N/A")),
438+
"requires": pep_info.get("requires"),
439+
"replaces": pep_info.get("replaces"),
440+
"superseded_by": pep_info.get("superseded_by"),
441+
"url": pep_info["url"],
442+
}
443+
for pep_info in data.values()
444+
]

0 commit comments

Comments
 (0)