1010import sys
1111import textwrap
1212from importlib .metadata import version
13- from typing import Literal , NamedTuple , NoReturn , TypedDict
13+ from typing import Literal , NamedTuple , NoReturn , TypedDict , cast
1414
1515import httpx
1616
6969# -------------------------------------------------------------------------------
7070
7171
72+ class AkismetArguments (TypedDict , total = False ):
73+ """
74+ A :class:`~typing.TypedDict` representing the optional keyword arguments accepted by
75+ most Akismet API operations.
76+
77+ """
78+
79+ blog_charset : str
80+ blog_lang : str
81+ comment_author : str
82+ comment_author_email : str
83+ comment_author_url : str
84+ comment_content : str
85+ comment_context : str
86+ comment_date_gmt : str
87+ comment_post_modified_gmt : str
88+ comment_type : str
89+ honeypot_field_name : str
90+ is_test : bool
91+ permalink : str
92+ recheck_reason : str
93+ referrer : str
94+ user_agent : str
95+ user_role : str
96+
97+
7298class CheckResponse (enum .IntEnum ):
7399 """
74100 Possible response values from an Akismet content check, including the
@@ -96,33 +122,11 @@ class Config(NamedTuple):
96122 url : str
97123
98124
99- class AkismetArguments (TypedDict , total = False ):
100- """
101- A :class:`~typing.TypedDict` representing the optional keyword arguments accepted by
102- most Akismet API operations.
103-
104- """
105-
106- blog_charset : str
107- blog_lang : str
108- comment_author : str
109- comment_author_email : str
110- comment_author_url : str
111- comment_content : str
112- comment_context : str
113- comment_date_gmt : str
114- comment_post_modified_gmt : str
115- comment_type : str
116- honeypot_field_name : str
117- is_test : bool
118- permalink : str
119- recheck_reason : str
120- referrer : str
121- user_agent : str
122- user_role : str
125+ # Private helper functions.
126+ # -------------------------------------------------------------------------------
123127
124128
125- # Private helper functions .
129+ # Functions which throw errors for various situations .
126130# -------------------------------------------------------------------------------
127131
128132
@@ -143,22 +147,6 @@ def _configuration_error(config: Config) -> NoReturn:
143147 )
144148
145149
146- def _get_async_http_client () -> httpx .AsyncClient :
147- """
148- Return an asynchronous HTTP client for interacting with the Akismet API.
149-
150- """
151- return httpx .AsyncClient (headers = {"User-Agent" : USER_AGENT }, timeout = _TIMEOUT )
152-
153-
154- def _get_sync_http_client () -> httpx .Client :
155- """
156- Return a synchronous HTTP client for interacting with the Akismet API.
157-
158- """
159- return httpx .Client (headers = {"User-Agent" : USER_AGENT }, timeout = _TIMEOUT )
160-
161-
162150def _protocol_error (operation : str , response : httpx .Response ) -> NoReturn :
163151 """
164152 Raise an appropriate exception for unexpected API responses.
@@ -177,6 +165,26 @@ def _protocol_error(operation: str, response: httpx.Response) -> NoReturn:
177165 )
178166
179167
168+ # Functions which help autodiscover/autofill configuration.
169+ # -------------------------------------------------------------------------------
170+
171+
172+ def _get_async_http_client () -> httpx .AsyncClient :
173+ """
174+ Return an asynchronous HTTP client for interacting with the Akismet API.
175+
176+ """
177+ return httpx .AsyncClient (headers = {"User-Agent" : USER_AGENT }, timeout = _TIMEOUT )
178+
179+
180+ def _get_sync_http_client () -> httpx .Client :
181+ """
182+ Return a synchronous HTTP client for interacting with the Akismet API.
183+
184+ """
185+ return httpx .Client (headers = {"User-Agent" : USER_AGENT }, timeout = _TIMEOUT )
186+
187+
180188def _try_discover_config () -> Config :
181189 """
182190 Attempt to discover and return an Akismet configuration from the environment.
@@ -207,14 +215,30 @@ def _try_discover_config() -> Config:
207215 f"""
208216 Invalid Akismet site URL specified: { url }
209217
210- Akismet requires the full URL including the leading
211- 'http://' or 'https://'.
218+ Akismet requires the full URL including the leading 'http://' or 'https://'.
212219 """
213220 )
214221 )
215222 return Config (key = key , url = url )
216223
217224
225+ # Functions which help process Akismet requests and responses.
226+ # -------------------------------------------------------------------------------
227+
228+
229+ def _handle_akismet_response (endpoint : str , response : httpx .Response ) -> httpx .Response :
230+ """
231+ Check the response to see if it indicates an invalid key.
232+
233+ """
234+ # It's possible to construct a client without performing up-front API key
235+ # validation, in which case the responses will all have text "invalid". So we check
236+ # for that and raise an exception when it's detected.
237+ if endpoint != _VERIFY_KEY and response .text == "invalid" :
238+ raise _exceptions .APIKeyError ("Akismet API key and/or site URL are invalid." )
239+ return response
240+
241+
218242def _handle_check_response (response : httpx .Response ) -> CheckResponse :
219243 """
220244 Return the correct result for a response from the comment-check endpoint.
@@ -229,7 +253,29 @@ def _handle_check_response(response: httpx.Response) -> CheckResponse:
229253 _protocol_error (_COMMENT_CHECK , response )
230254
231255
232- def _check_post_kwargs (kwargs : dict , endpoint : str ) -> AkismetArguments :
256+ def _handle_submit_response (endpoint : str , response : httpx .Response ) -> bool :
257+ """
258+ Proces the response from a submit (ham/spam) request.
259+
260+ """
261+ if response .text == _SUBMISSION_RESPONSE :
262+ return True
263+ _protocol_error (endpoint , response )
264+
265+
266+ def _handle_verify_key_response (response : httpx .Response ) -> bool :
267+ """
268+ Handle the response from a verify_key() request.
269+
270+ """
271+ if response .text == "valid" :
272+ return True
273+ if response .text == "invalid" :
274+ return False
275+ _protocol_error (_VERIFY_KEY , response )
276+
277+
278+ def _prepare_post_kwargs (kwargs : dict , endpoint : str ) -> AkismetArguments :
233279 """
234280 Verify that the provided set of keyword arguments is valid for an Akismet POST
235281 request, returning them if they are or raising UnknownArgumentError if they aren't.
@@ -240,7 +286,7 @@ def _check_post_kwargs(kwargs: dict, endpoint: str) -> AkismetArguments:
240286 f"Received unknown argument(s) for Akismet operation { endpoint } : "
241287 f"{ ', ' .join (unknown_args )} "
242288 )
243- return kwargs
289+ return cast ( AkismetArguments , kwargs )
244290
245291
246292def _prepare_request (
@@ -257,38 +303,3 @@ def _prepare_request(
257303 )
258304 request_kwarg = "data" if method == "POST" else "params"
259305 return f"{ _API_URL } /{ api_version } /{ endpoint } " , {request_kwarg : data }
260-
261-
262- def _akismet_response (endpoint : str , response : httpx .Response ) -> httpx .Response :
263- """
264- Check the response to see if it indicates an invalid key.
265-
266- """
267- # It's possible to construct a client without performing up-front API key
268- # validation, in which case the responses will all have text "invalid". So we check
269- # for that and raise an exception when it's detected.
270- if endpoint != _VERIFY_KEY and response .text == "invalid" :
271- raise _exceptions .APIKeyError ("Akismet API key and/or site URL are invalid." )
272- return response
273-
274-
275- def _submit_response (endpoint : str , response : httpx .Response ) -> bool :
276- """
277- Proces the response from a submit (ham/spam) request.
278-
279- """
280- if response .text == _SUBMISSION_RESPONSE :
281- return True
282- _protocol_error (endpoint , response )
283-
284-
285- def _verify_key_response (response : httpx .Response ) -> bool :
286- """
287- Handle the response from a verify_key() request.
288-
289- """
290- if response .text == "valid" :
291- return True
292- if response .text == "invalid" :
293- return False
294- _protocol_error (_VERIFY_KEY , response )
0 commit comments