Site: Store namespace information in self._namespaces, a dict where key is a namespace ID and value is a list of matching names and aliases; added _get_namespaces_from_api(), namespaces(), namespace_id_to_name() and namespace_name_to_id(); get_page() and get_category() are smarter; Constants: new module, with 18 variables starting with "NS_" that hold IDs of common namespaces, e.g NS_USER = 2, NS_PROJECT = 4; Exceptions: added NamespaceNotFoundError, raised by Site when bad input is given to namespace_id_to_name() or namespace_name_to_id(); User: self.name -> self._name; new name() method returns name from API; dropping "get" from methods that return just a variable; Category: get_members() -> members().tags/v0.1^2
@@ -10,6 +10,7 @@ written by Mr.Z-man, other than a similar purpose. We share no code. | |||||
Import the toolset with `from wiki import tools`. | Import the toolset with `from wiki import tools`. | ||||
""" | """ | ||||
from wiki.tools.constants import * | |||||
from wiki.tools.exceptions import * | from wiki.tools.exceptions import * | ||||
from wiki.tools.functions import * | from wiki.tools.functions import * | ||||
@@ -7,7 +7,7 @@ class Category(Page): | |||||
EarwigBot's Wiki Toolset: Category Class | EarwigBot's Wiki Toolset: Category Class | ||||
""" | """ | ||||
def get_members(self, limit=50): | |||||
def members(self, limit=50): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
@@ -0,0 +1,27 @@ | |||||
# -*- coding: utf-8 -*- | |||||
""" | |||||
EarwigBot's Wiki Toolset: Constants | |||||
This module defines some useful constants. | |||||
""" | |||||
# Default namespace IDs | |||||
NS_MAIN = 0 | |||||
NS_TALK = 1 | |||||
NS_USER = 2 | |||||
NS_USER_TALK = 3 | |||||
NS_PROJECT = 4 | |||||
NS_PROJECT_TALK = 5 | |||||
NS_FILE = 6 | |||||
NS_FILE_TALK = 7 | |||||
NS_MEDIAWIKI = 8 | |||||
NS_MEDIAWIKI_TALK = 9 | |||||
NS_TEMPLATE = 10 | |||||
NS_TEMPLATE_TALK = 11 | |||||
NS_HELP = 12 | |||||
NS_HELP_TALK = 13 | |||||
NS_CATEGORY = 14 | |||||
NS_CATEGORY_TALK = 15 | |||||
NS_SPECIAL = -1 | |||||
NS_MEDIA = -2 |
@@ -13,5 +13,8 @@ class SiteNotFoundError(WikiToolsetError): | |||||
"""A site matching the args given to get_site() could not be found in the | """A site matching the args given to get_site() could not be found in the | ||||
config file.""" | config file.""" | ||||
class NamespaceNotFoundError(WikiToolsetError): | |||||
"""A requested namespace name or namespace ID does not exist.""" | |||||
class UserNotFoundError(WikiToolsetError): | class UserNotFoundError(WikiToolsetError): | ||||
"""Attempting to get information about a user that does not exist.""" | """Attempting to get information about a user that does not exist.""" |
@@ -23,7 +23,7 @@ class Page(object): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
if content is None or force_reload: | |||||
if self._content is None or force_reload: | |||||
params = {"action": "query", "prop": "revisions", | params = {"action": "query", "prop": "revisions", | ||||
"rvprop": "content", "rvlimit": 1, "titles": self.title} | "rvprop": "content", "rvlimit": 1, "titles": self.title} | ||||
result = self.site.api_query(params) | result = self.site.api_query(params) | ||||
@@ -5,6 +5,8 @@ from urllib import urlencode | |||||
from urllib2 import urlopen | from urllib2 import urlopen | ||||
from wiki.tools.category import Category | from wiki.tools.category import Category | ||||
from wiki.tools.constants import * | |||||
from wiki.tools.exceptions import NamespaceNotFoundError | |||||
from wiki.tools.page import Page | from wiki.tools.page import Page | ||||
from wiki.tools.user import User | from wiki.tools.user import User | ||||
@@ -22,6 +24,37 @@ class Site(object): | |||||
self.lang = lang | self.lang = lang | ||||
self._api = api | self._api = api | ||||
self._sql = sql | self._sql = sql | ||||
self._namespaces = None | |||||
def _get_namespaces_from_api(self): | |||||
""" | |||||
Docstring needed | |||||
""" | |||||
params = {"action": "query", "meta": "siteinfo", | |||||
"siprop": "namespaces|namespacealiases"} | |||||
result = self.api_query(params) | |||||
if self._namespaces is None: | |||||
self._namespaces = {} | |||||
for namespace in result["query"]["namespaces"].values(): | |||||
ns_id = namespace["id"] | |||||
name = namespace["*"] | |||||
try: | |||||
canonical = namespace["canonical"] | |||||
except KeyError: | |||||
self._namespaces[ns_id] = [name] | |||||
else: | |||||
if name != canonical: | |||||
self._namespaces[ns_id] = [name, canonical] | |||||
else: | |||||
self._namespaces[ns_id] = [name] | |||||
for namespace in result["query"]["namespacealiases"]: | |||||
ns_id = namespace["id"] | |||||
alias = namespace["*"] | |||||
self._namespaces[ns_id].append(alias) | |||||
def api_query(self, params): | def api_query(self, params): | ||||
""" | """ | ||||
@@ -32,19 +65,65 @@ class Site(object): | |||||
result = urlopen(self._api, data).read() | result = urlopen(self._api, data).read() | ||||
return loads(result) | return loads(result) | ||||
def namespaces(self): | |||||
""" | |||||
Docstring needed | |||||
""" | |||||
if self._namespaces is None: | |||||
self._get_namespaces_from_api() | |||||
return self._namespaces | |||||
def namespace_id_to_name(self, ns_id, all=False): | |||||
""" | |||||
Docstring needed | |||||
""" | |||||
if self._namespaces is None: | |||||
self._get_namespaces_from_api() | |||||
try: | |||||
if all: | |||||
return self._namespaces[ns_id] | |||||
else: | |||||
return self._namespaces[ns_id][0] | |||||
except KeyError: | |||||
e = "There is no namespace with id {0}.".format(ns_id) | |||||
raise NamespaceNotFoundError(e) | |||||
def namespace_name_to_id(self, name): | |||||
""" | |||||
Docstring needed | |||||
""" | |||||
if self._namespaces is None: | |||||
self._get_namespaces_from_api() | |||||
lname = name.lower() | |||||
for ns_id, names in self._namespaces.items(): | |||||
lnames = [n.lower() for n in names] # be case-insensitive | |||||
if lname in lnames: | |||||
return ns_id | |||||
e = "There is no namespace with name '{0}'.".format(name) | |||||
raise NamespaceNotFoundError(e) | |||||
def get_page(self, pagename): | def get_page(self, pagename): | ||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
if pagename.startswith("Category:"): # proper namespace checking! | |||||
return get_category(pagename[9:]) | |||||
prefixes = self.namespace_id_to_name(NS_CATEGORY, all=True) | |||||
prefix = pagename.split(":", 1)[0] | |||||
if prefix != pagename: # avoid a page that is simply "Category" | |||||
if prefix in prefixes: | |||||
return Category(self, pagename) | |||||
return Page(self, pagename) | return Page(self, pagename) | ||||
def get_category(self, catname): | def get_category(self, catname): | ||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return Category(self, "Category:" + catname) # namespace checking! | |||||
prefix = self.namespace_id_to_name(NS_CATEGORY) | |||||
pagename = "{0}:{1}".format(prefix, catname) | |||||
return Category(self, pagename) | |||||
def get_user(self, username): | def get_user(self, username): | ||||
""" | """ | ||||
@@ -1,5 +1,6 @@ | |||||
# -*- coding: utf-8 -*- | # -*- coding: utf-8 -*- | ||||
from wiki.tools.constants import * | |||||
from wiki.tools.exceptions import UserNotFoundError | from wiki.tools.exceptions import UserNotFoundError | ||||
from wiki.tools.page import Page | from wiki.tools.page import Page | ||||
@@ -12,9 +13,11 @@ class User(object): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
# Public attributes | |||||
self.site = site # Site instance, for doing API queries, etc | |||||
self.name = name # our username | |||||
# Site instance, for doing API queries, etc | |||||
self.site = site | |||||
# Username | |||||
self._name = name | |||||
# Attributes filled in by an API query | # Attributes filled in by an API query | ||||
self._exists = None | self._exists = None | ||||
@@ -34,19 +37,20 @@ class User(object): | |||||
if self._exists is None or force: | if self._exists is None or force: | ||||
self._load_attributes_from_api() | self._load_attributes_from_api() | ||||
if self._exists is False: | if self._exists is False: | ||||
raise UserNotFoundError("User '{0}' does not exist.".format(self.name)) | |||||
e = "User '{0}' does not exist.".format(self._name) | |||||
raise UserNotFoundError(e) | |||||
return getattr(self, attr) | return getattr(self, attr) | ||||
def _load_attributes_from_api(self): | def _load_attributes_from_api(self): | ||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
params = {"action": "query", "list": "users", "ususers": self.name, | |||||
params = {"action": "query", "list": "users", "ususers": self._name, | |||||
"usprop": "blockinfo|groups|rights|editcount|registration|emailable|gender"} | "usprop": "blockinfo|groups|rights|editcount|registration|emailable|gender"} | ||||
result = self.site.api_query(params) | result = self.site.api_query(params) | ||||
# normalize our username in case it was entered oddly | # normalize our username in case it was entered oddly | ||||
self.name = result["query"]["users"][0]["name"] | |||||
self._name = result["query"]["users"][0]["name"] | |||||
try: | try: | ||||
self._userid = result["query"]["users"][0]["userid"] | self._userid = result["query"]["users"][0]["userid"] | ||||
@@ -76,68 +80,78 @@ class User(object): | |||||
except KeyError: | except KeyError: | ||||
self._blockinfo = False | self._blockinfo = False | ||||
def name(self, force=False): | |||||
""" | |||||
Docstring needed | |||||
""" | |||||
return self._get_attribute_from_api("_name", force) | |||||
def exists(self, force=False): | def exists(self, force=False): | ||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return self._get_attribute_from_api("_exists", force) | return self._get_attribute_from_api("_exists", force) | ||||
def get_userid(self, force=False): | |||||
def userid(self, force=False): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return self._get_attribute_from_api("_userid", force) | return self._get_attribute_from_api("_userid", force) | ||||
def get_blockinfo(self, force=False): | |||||
def blockinfo(self, force=False): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return self._get_attribute_from_api("_blockinfo", force) | return self._get_attribute_from_api("_blockinfo", force) | ||||
def get_groups(self, force=False): | |||||
def groups(self, force=False): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return self._get_attribute_from_api("_groups", force) | return self._get_attribute_from_api("_groups", force) | ||||
def get_rights(self, force=False): | |||||
def rights(self, force=False): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return self._get_attribute_from_api("_rights", force) | return self._get_attribute_from_api("_rights", force) | ||||
def get_editcount(self, force=False): | |||||
def editcount(self, force=False): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return self._get_attribute_from_api("_editcount", force) | return self._get_attribute_from_api("_editcount", force) | ||||
def get_registration(self, force=False): | |||||
def registration(self, force=False): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return self._get_attribute_from_api("_registration", force) | return self._get_attribute_from_api("_registration", force) | ||||
def get_emailable(self, force=False): | |||||
def is_emailable(self, force=False): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return self._get_attribute_from_api("_emailable", force) | return self._get_attribute_from_api("_emailable", force) | ||||
def get_gender(self, force=False): | |||||
def gender(self, force=False): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return self._get_attribute_from_api("_gender", force) | return self._get_attribute_from_api("_gender", force) | ||||
def get_userpage(self): | |||||
def userpage(self): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return Page(self.site, "User:" + self.name) # Namespace checking! | |||||
prefix = self.site.namespace_id_to_name(NS_USER) | |||||
pagename = "{0}:{1}".format(prefix, self._name) | |||||
return Page(self.site, pagename) | |||||
def get_talkpage(self): | |||||
def talkpage(self): | |||||
""" | """ | ||||
Docstring needed | Docstring needed | ||||
""" | """ | ||||
return Page(self.site, "User talk:" + self.name) # Namespace checking! | |||||
prefix = self.site.namespace_id_to_name(NS_USER_TALK) | |||||
pagename = "{0}:{1}".format(prefix, self._name) | |||||
return Page(self.site, pagename) |