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) | |||||