Skip to content

Commit 91cf282

Browse files
committed
sanity refactors, more docs, more tests
1 parent a386c49 commit 91cf282

File tree

10 files changed

+166
-100
lines changed

10 files changed

+166
-100
lines changed

pwiki/dwrap.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,16 @@
88
class _DataEntry:
99
"""Base template class for more structured data returned by the API."""
1010

11-
def __init__(self, user: str = None, title: str = None, summary: str = None, timestamp: str = None):
11+
def __init__(self, e: dict):
1212
"""Initializer, creates a new DataEntry.
1313
1414
Args:
15-
user (str, optional): The user associated with this entry. `User:` prefix should be omitted. Defaults to None.
16-
title (str, optional): The page title associated with this entry. Defaults to None.
17-
summary (str, optional): The summary associated with this entry. Defaults to None.
18-
timestamp (str, optional): The timestamp (in ISO 8601) the entry occured at. Defaults to None.
15+
e (dict): A json object from the list in the response from the server.
1916
"""
20-
self.user: str = user
21-
self.title: str = title
22-
self.summary: str = summary
23-
self.timestamp: datetime = datetime.fromisoformat(timestamp.replace("Z", "+00:00")) if timestamp else None
17+
self.user: str = e.get("user")
18+
self.title: str = e.get("title")
19+
self.summary: str = e.get("comment")
20+
self.timestamp: datetime = datetime.fromisoformat(ts.replace("Z", "+00:00")) if (ts := e.get("timestamp")) else None
2421

2522
def __repr__(self) -> str:
2623
"""Creates a str representation of this DataEntry. Useful for debugging.
@@ -40,7 +37,7 @@ def __init__(self, e: dict):
4037
Args:
4138
e (dict): A json object from the `"contributions"` list in the response from the server.
4239
"""
43-
super().__init__(e.get("user"), e.get("title"), e.get("comment"), e.get("timestamp"))
40+
super().__init__(e)
4441

4542
self.is_page_create: bool = e.get("new")
4643
self.is_minor: bool = e.get("minor")
@@ -56,7 +53,7 @@ def __init__(self, e: dict):
5653
Args:
5754
e (dict): A json object from the `"imageinfo"` list in the response from the server.
5855
"""
59-
super().__init__(e.get("user"), summary=e.get("comment"), timestamp=e.get("timestamp"))
56+
super().__init__(e)
6057

6158
self.size: int = e.get("size")
6259
self.width: int = e.get("width")
@@ -74,7 +71,7 @@ def __init__(self, e: dict):
7471
Args:
7572
e (dict): A json object from the `"logevents"` list in the response from the server.
7673
"""
77-
super().__init__(e.get("user"), e.get("title"), e.get("comment"), e.get("timestamp"))
74+
super().__init__(e)
7875

7976
self.type: str = e.get("type")
8077
self.action: str = e.get("action")
@@ -90,7 +87,7 @@ def __init__(self, e: dict):
9087
Args:
9188
e (dict): A json object from the `"revisions"` list in the response from the server.
9289
"""
93-
super().__init__(e.get("user"), summary=e.get("comment"), timestamp=e.get("timestamp"))
90+
super().__init__(e)
9491

9592
self.text: str = mine_for(e, "slots", "main", "content")
9693

pwiki/oquery.py

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -41,50 +41,6 @@ def _pair_titles_query(wiki: Wiki, id: str, pl: dict, titles: list[str], desc: s
4141

4242
return out
4343

44-
# @staticmethod
45-
# def _prop_cont_single(wiki: Wiki, title: str, template: QConstant, extra_pl: dict = None) -> list:
46-
# out = []
47-
48-
# params = {**template.pl_with_limit(), "prop": template.name, "titles": title} | (extra_pl or {})
49-
50-
# while True:
51-
# if not (response := query_and_validate(wiki, params, desc=f"peform a prop_cont_single query with '{template.name}'")):
52-
# raise OSError(f"Critical failure performing a _prop_cont_single query with {template.name}, cannot proceed")
53-
54-
# if not ((l := mine_for(response, "query", "pages")) and template.name in (p := l[0])):
55-
# break
56-
57-
# out += template.retrieve_results(p[template.name])
58-
59-
# if not (cont := get_continue_params(response)):
60-
# break
61-
62-
# params.update(cont)
63-
64-
# return out
65-
66-
# @staticmethod
67-
# def _list_cont(wiki: Wiki, template: QConstant, extra_pl: dict = None) -> list:
68-
# out = []
69-
70-
# params = {**template.pl_with_limit(), "list": template.name} | (extra_pl or {})
71-
# while True:
72-
# if not (response := query_and_validate(wiki, params, desc=f"peform a list_cont query with '{template.name}'")):
73-
# return
74-
75-
# if template.name not in (q := mine_for(response, "query")):
76-
# log.error("'%s' was not found in query result while doing a list_cont, something is very wrong.", template.name)
77-
# return
78-
79-
# out += template.retrieve_results(q[template.name])
80-
81-
# if not (cont := get_continue_params(response)):
82-
# break
83-
84-
# params.update(cont)
85-
86-
# return out
87-
8844
@staticmethod
8945
def fetch_token(wiki: Wiki, login_token: bool = False) -> str:
9046
"""Fetch a csrf or login token from the server. By default, this method will retrieve a csrf token.

pwiki/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def mine_for(target: dict, *keys: str) -> Any:
4242
keys (str): The keys to follow.
4343
4444
Returns:
45-
Any: Whatever value is found at the end of following the specified keys. None if nothing was not found.
45+
Any: Whatever value is found at the end of following the specified keys. `None` if nothing was not found.
4646
"""
4747
try:
4848
for k in keys:

pwiki/waction.py

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,21 @@ class WAction:
2222
"""Collection of functions which can perform write actions on a Wiki"""
2323

2424
@staticmethod
25-
def _post_action(wiki: Wiki, action: str, form: dict = None, apply_token: bool = True, timeout: int = 15, extra_args: dict = None) -> dict:
26-
"""Convienence method, performs the actual POST of the action to the server.
25+
def _action_and_validate(wiki: Wiki, action: str, form: dict = None, apply_token: bool = True, timeout: int = 15, success_vals: tuple = ("Success",), extra_args: dict = None) -> dict:
26+
"""Performs a `_post_action()` and checks the results for errors. If there is an error, it will be logged accordingly.
2727
2828
Args:
2929
wiki (Wiki): The Wiki object to use
30-
action (str): The action to perform.
30+
action (str): The id of the action to perform.
3131
form (dict, optional): The parameters to POST to the server, if applicable. Defaults to None.
3232
apply_token (bool, optional): Set `True` to also send the Wiki's csrf token in the POST. Defaults to True.
33+
timeout (int, optional): The length of time (in seconds) to wait before marking the action as failed. Defaults to 15.
34+
success_vals (tuple, optional): The keyword responses returned by the server which indicate a successful action. Optional, set `None` to skip this check. Defaults to ("Success",).
35+
extra_args (dict, optional): Any `kwargs` that should be passed to the underlying requests Session object when performing a POST. Defaults to None.
3336
3437
Returns:
35-
dict: The response from the server. Empty dict if there was an error.
38+
dict: The json response from the server, or `None` if something went wrong.
3639
"""
37-
pl = make_params(action, form) | ({"token": wiki.csrf_token} if apply_token else {})
38-
39-
try:
40-
return wiki.client.post(wiki.endpoint, data=pl, **({"timeout": timeout} | (extra_args or {}))).json()
41-
except Exception:
42-
log.error("%s: Could not reach server or read response while performing %s with params %s", wiki, action, pl, exc_info=True)
43-
44-
return {}
45-
46-
@staticmethod
47-
def _action_and_validate(wiki: Wiki, action: str, form: dict = None, apply_token: bool = True, timeout: int = 15, success_vals: tuple = ("Success",), extra_args: dict = None) -> dict:
48-
4940
if not (response := WAction._post_action(wiki, action, form, apply_token, timeout, extra_args)):
5041
log.error("%s: No response from server while trying to perform action '%s'", wiki, action)
5142
log.debug("Sent parameters: %s", form)
@@ -56,12 +47,36 @@ def _action_and_validate(wiki: Wiki, action: str, form: dict = None, apply_token
5647
log.debug(response)
5748
return
5849

59-
if (status := mine_for(response, action, "result")) in success_vals:
50+
if not success_vals or (status := mine_for(response, action, "result")) in success_vals:
6051
return response
6152

6253
log.error("%s: Failed to perform action '%s', got bad result from server: %s", wiki, action, status)
6354
log.debug(response)
6455

56+
@staticmethod
57+
def _post_action(wiki: Wiki, action: str, form: dict = None, apply_token: bool = True, timeout: int = 15, extra_args: dict = None) -> dict:
58+
"""Convienence method, performs the actual POST of the action to the server.
59+
60+
Args:
61+
wiki (Wiki): The Wiki object to use
62+
action (str): The action to perform.
63+
form (dict, optional): The parameters to POST to the server, if applicable. Defaults to None.
64+
apply_token (bool, optional): Set `True` to also send the Wiki's csrf token in the POST. Defaults to True.
65+
timeout (int, optional): The length of time (in seconds) to wait before marking the action as failed. Defaults to 15.
66+
extra_args (dict, optional): Any `kwargs` that should be passed to the underlying requests Session object when performing a POST. Defaults to None.
67+
68+
Returns:
69+
dict: The response from the server. Empty dict if there was an error.
70+
"""
71+
pl = make_params(action, form) | ({"token": wiki.csrf_token} if apply_token else {})
72+
73+
try:
74+
return wiki.client.post(wiki.endpoint, data=pl, **({"timeout": timeout} | (extra_args or {}))).json()
75+
except Exception:
76+
log.error("%s: Could not reach server or read response while performing %s with params %s", wiki, action, pl, exc_info=True)
77+
78+
return {}
79+
6580
@staticmethod
6681
def delete(wiki: Wiki, title: str, reason: str) -> bool:
6782
"""Deletes a page. PRECONDITION: `wiki` must be logged in and have the ability to delete pages for this to work.
@@ -74,7 +89,7 @@ def delete(wiki: Wiki, title: str, reason: str) -> bool:
7489
Returns:
7590
bool: `True` if this action succeeded.
7691
"""
77-
return bool(WAction._action_and_validate(wiki, "delete", {"title": title, "reason": reason}))
92+
return bool(WAction._action_and_validate(wiki, "delete", {"title": title, "reason": reason}, success_vals=None))
7893

7994
@staticmethod
8095
def edit(wiki: Wiki, title: str, text: str = None, summary: str = "", prepend: str = None, append: str = None, minor: bool = False) -> bool:
@@ -83,10 +98,10 @@ def edit(wiki: Wiki, title: str, text: str = None, summary: str = "", prepend: s
8398
Args:
8499
wiki (Wiki): The Wiki to use.
85100
title (str): The title to edit.
86-
text (str, optional): Text to replace the current page's contents with. Mutually exclusive with `prepend`/`append`. Defaults to None.
101+
text (str, optional): Text to replace the current page's contents with. Overrides `prepend`/`append`. Defaults to None.
87102
summary (str, optional): The edit summary to use. Defaults to "".
88-
prepend (str, optional): Text to prepend to the page. Mutually exclusive with `text`. Defaults to None.
89-
append (str, optional): Text to append to the page. Mutually exclusive with `text`. Defaults to None.
103+
prepend (str, optional): Text to prepend to the page. Defaults to None.
104+
append (str, optional): Text to append to the page. Defaults to None.
90105
minor (bool, optional): Set `True` to mark this edit as minor. Defaults to False.
91106
92107
Raises:

0 commit comments

Comments
 (0)