Skip to content

Commit 61375a5

Browse files
committed
Add supported lexer validation to paste service and default the paste_url
1 parent b3425c4 commit 61375a5

File tree

3 files changed

+36
-6
lines changed

3 files changed

+36
-6
lines changed

docs/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
44
Changelog
55
=========
6+
- :release:`9.9.0 <18th June 2023>`
7+
- :feature:`182` Default pastebin url to https://paste.pythondiscord.com
8+
- :feature:`182` Add supported lexer validation to paste service.
9+
10+
611
- :release:`9.8.0 <13th June 2023>`
712
- :support:`181` Bump Discord.py to :literal-url:`2.3.0 <https://github.com/Rapptz/discord.py/releases/tag/v2.3.0>`.
813

pydis_core/utils/paste_service.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
from typing import TypedDict
23

34
from aiohttp import ClientConnectorError, ClientSession
@@ -6,10 +7,14 @@
67

78
log = logging.get_logger(__name__)
89

10+
DEFAULT_PASTEBIN = "https://paste.pythondiscord.com"
911
FAILED_REQUEST_ATTEMPTS = 3
10-
MAX_PASTE_SIZE = 128 * 1024 # 128kB
12+
MAX_PASTE_SIZE = 512 * 1024 # 512kB
1113
"""The maximum allows size of a paste, in bytes."""
1214

15+
# A dict where the keys are paste services and the keys are the lists of lexers that paste service supports.
16+
_lexers_supported_by_pastebin: dict[str,list[str]] = {}
17+
1318

1419
class PasteResponse(TypedDict):
1520
"""
@@ -27,6 +32,9 @@ class PasteResponse(TypedDict):
2732
class PasteUploadError(Exception):
2833
"""Raised when an error is encountered uploading to the paste service."""
2934

35+
class PasteUnsupportedLexerError(Exception):
36+
"""Raised when an unsupported lexer is used."""
37+
3038

3139
class PasteTooLongError(Exception):
3240
"""Raised when content is too large to upload to the paste service."""
@@ -35,21 +43,21 @@ class PasteTooLongError(Exception):
3543
async def send_to_paste_service(
3644
*,
3745
contents: str,
38-
paste_url: str,
3946
http_session: ClientSession,
4047
file_name: str = "",
4148
lexer: str = "python",
49+
paste_url: str = DEFAULT_PASTEBIN,
4250
max_size: int = MAX_PASTE_SIZE,
4351
) -> PasteResponse:
4452
"""
4553
Upload some contents to the paste service.
4654
4755
Args:
4856
contents: The content to upload to the paste service.
49-
paste_url: The base url to the paste service.
5057
http_session (aiohttp.ClientSession): The session to use when POSTing the content to the paste service.
5158
file_name: The name of the file to save to the paste service.
5259
lexer: The lexer to save the content with.
60+
paste_url: The base url to the paste service.
5361
max_size: The max number of bytes to be allowed. Anything larger than :obj:`MAX_PASTE_SIZE` will be rejected.
5462
5563
Raises:
@@ -63,6 +71,18 @@ async def send_to_paste_service(
6371
if max_size > MAX_PASTE_SIZE:
6472
raise ValueError(f"`max_length` must not be greater than {MAX_PASTE_SIZE}")
6573

74+
if paste_url not in _lexers_supported_by_pastebin:
75+
try:
76+
async with http_session.get(f"{paste_url}/api/v1/lexer") as response:
77+
response_json = await response.json() # Supported lexers are the keys.
78+
except Exception:
79+
raise PasteUploadError("Could not fetch supported lexers from selected paste_url.")
80+
81+
_lexers_supported_by_pastebin[paste_url] = list(response_json)
82+
83+
if lexer not in _lexers_supported_by_pastebin[paste_url]:
84+
raise PasteUnsupportedLexerError(f"Lexer '{lexer}' not supported by pastebin.")
85+
6686
contents_size = len(contents.encode())
6787
if contents_size > max_size:
6888
log.info("Contents too large to send to paste service.")
@@ -79,7 +99,7 @@ async def send_to_paste_service(
7999
for attempt in range(1, FAILED_REQUEST_ATTEMPTS + 1):
80100
try:
81101
async with http_session.post(f"{paste_url}/api/v1/paste", json=payload) as response:
82-
response_json = await response.json()
102+
response_text = await response.text()
83103
except ClientConnectorError:
84104
log.warning(
85105
f"Failed to connect to paste service at url {paste_url}, "
@@ -94,12 +114,17 @@ async def send_to_paste_service(
94114
continue
95115

96116
if response.status == 400:
117+
if "Text exceeds size limit" in response_text:
118+
log.info("Contents too large to send to paste service after lexing.")
119+
raise PasteTooLongError(
120+
f"Contents of size {contents_size} greater than maximum size {max_size} after lexing"
121+
)
97122
log.warning(
98123
f"Paste service returned error {response_json['message']} with status code {response.status}, "
99124
f"trying again ({attempt}/{FAILED_REQUEST_ATTEMPTS})."
100125
)
101126
continue
102-
127+
response_json = json.loads(response_text)
103128
if response.status == 200:
104129
log.info(f"Successfully uploaded contents to {response_json['link']}.")
105130
return PasteResponse(link=response_json["link"], removal=response_json["removal"])

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "pydis_core"
3-
version = "9.8.0"
3+
version = "9.9.0"
44
description = "PyDis core provides core functionality and utility to the bots of the Python Discord community."
55
authors = ["Python Discord <info@pythondiscord.com>"]
66
license = "MIT"

0 commit comments

Comments
 (0)