* Site: api_query() -> _api_query(); api_query() acts as a wrapper for _api_query(), accepting API params as **kwargs.
* Various cleanup throughout and minor fixes.
* Exceptions: New PermissionsError; reworded docstring of SiteAPIError.
* Site: __init__() accepts an optional cookiejar parameter, otherwise we
use CookieJar(). Added five new cookie/username-related methods. Only
login from __init__() if we are missing valid login cookies and a user/
pass was provided. _login() and _logout() both try to save cookies via
_save_cookiejar(). _load_attributes() automatically refreshes all
attributes other than namespaces if at least one is missing, instead of
only the missing ones. api_query() raises SiteAPIError if either
self._base_url or self._script_path is missing. Removed some pointless
methods and renamed one; added domain().
* Functions: _get_site_object_from_dict() is cleaner, adds our cookiejar
to Site instances using _get_cookiejar() to load a LWPCookieJar() object
from the ".cookies" file in our project root. The same cookiejar is
returned for every site, enabling crosswiki login, via a global variable.
* User: Renamed some methods.
* .gitignore: Added .cookies file.
* Site: New _get_logged_in_user() method, name self-explanatory. This acts
as a replacement for the former crud in get_user(), which now calls this
when the username arg is None. This method will first try to determine
our username based on a special cookie in self._cookiejar (cookie.name is
self._name + "UserName", e.g. "enwikiUserName"), and will only do an API
query if no cookie was found. This removes an API query that is usually
only necessary if we are not logged in.
* Site: silly bugfix in __init__().
* User: Reverted earlier change to _get_attribute() (addition of
raise_exception arg); name() and exists() now use their own code, which
is simpler.
* User: Calling name() does not do an API query unless force=True, unlike
the other "get" methods.
* User: .join() instead of .format() because I feel it looks cleaner and is
probably more efficient.
* Site's api_query() is much smarter. It uses a custom urllib2 URL opener with cookie support and catches URLErrors, raising its own brand new exception (SiteAPIError) when something is wrong.
* The opener now uses a custom User-Agent, which is a constant in wiki.tools.constants.
* Site instances automatically login via _login(), which accepts a username and password (provided via config by get_site()) and uses two api_query()s and stores the login data as cookies in self._cookiejar. Login data is not preserved between bot restarts yet. Login errors, e.g. a bad password or username, raise the new LoginError.
* Site's get_user()'s username argument is now optional. If left blank, will return the current logged-in user, provided by an API query.
* Misc cleanup throughout.
* Site's __init__() takes more args, all optional. As long as enough are
provided to do an API query, the missing ones will be filled in
automatically by _load_attributes(), which is called in __init__().
* User: _get_attribute_from_api() -> _get_attribute();
_load_attributes_from_api() -> _load_attributes.
* Sites in config.json are stored with different keys/values.
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().
* Got rid of ConfigError from exceptions.py.
* Try to load config ourselves if it isn't already, via the new _load_config()
method of Site. It uses getpass if passwords are encrypted, as done by
earwigbot.py.
* Cleaned up UserNotFoundError in user.py and exceptions.py.