1+ import json
12from typing import TypedDict
23
34from aiohttp import ClientConnectorError , ClientSession
67
78log = logging .get_logger (__name__ )
89
10+ DEFAULT_PASTEBIN = "https://paste.pythondiscord.com"
911FAILED_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
1419class PasteResponse (TypedDict ):
1520 """
@@ -27,6 +32,9 @@ class PasteResponse(TypedDict):
2732class 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
3139class PasteTooLongError (Exception ):
3240 """Raised when content is too large to upload to the paste service."""
@@ -35,21 +43,21 @@ class PasteTooLongError(Exception):
3543async 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 } , "
@@ -93,6 +113,13 @@ async def send_to_paste_service(
93113 )
94114 continue
95115
116+ if "Text exceeds size limit" in response_text :
117+ log .info ("Contents too large to send to paste service after lexing." )
118+ raise PasteTooLongError (
119+ f"Contents of size { contents_size } greater than maximum size { max_size } after lexing"
120+ )
121+
122+ response_json = json .loads (response_text )
96123 if response .status == 400 :
97124 log .warning (
98125 f"Paste service returned error { response_json ['message' ]} with status code { response .status } , "
0 commit comments