[Pywikipedia-l] SVN: [5675] trunk/pywikipedia

siebrand at svn.wikimedia.org siebrand at svn.wikimedia.org
Sat Jul 5 18:21:04 UTC 2008


Revision: 5675
Author:   siebrand
Date:     2008-07-05 18:21:03 +0000 (Sat, 05 Jul 2008)

Log Message:
-----------
svn:eol-style:native

Modified Paths:
--------------
    trunk/pywikipedia/archive/mediawiki_messages.py
    trunk/pywikipedia/category_redirect.py
    trunk/pywikipedia/commonsdelinker/plugins.txt
    trunk/pywikipedia/families/README-family.txt
    trunk/pywikipedia/protect.py

Property Changed:
----------------
    trunk/pywikipedia/archive/mediawiki_messages.py
    trunk/pywikipedia/category_redirect.py
    trunk/pywikipedia/commonsdelinker/plugins.txt
    trunk/pywikipedia/families/README-family.txt
    trunk/pywikipedia/protect.py

Modified: trunk/pywikipedia/archive/mediawiki_messages.py
===================================================================
--- trunk/pywikipedia/archive/mediawiki_messages.py	2008-07-05 12:57:13 UTC (rev 5674)
+++ trunk/pywikipedia/archive/mediawiki_messages.py	2008-07-05 18:21:03 UTC (rev 5675)
@@ -1,218 +1,218 @@
-# -*- coding: utf-8 -*-
-"""
-Allows access to the MediaWiki messages, that's the label texts of the MediaWiki
-software in the current language. These can be used in other bots.
-
-The function refresh_messages() downloads all the current messages and saves
-them to disk. It is run automatically when a bot first tries to access one of
-the messages. It can be updated manually by running this script, e.g. when
-somebody changed the current message at the wiki. The texts will also be
-reloaded automatically once a month.
-
-Syntax: python mediawiki_messages [-all]
-
-Command line options:
-    -refresh - Reloads messages for the home wiki or for the one defined via
-               the -lang and -family parameters.
-
-    -all     - Reloads messages for all wikis where messages are already present
-
-    If another parameter is given, it will be interpreted as a MediaWiki key.
-    The script will then output the respective value, without refreshing..
-    
-"""
-
-# (C) Daniel Herding, 2004
-#
-# Distributed under the terms of the MIT license.
-
-##THIS MODULE IS DEPRECATED AND HAS BEEN REPLACED BY NEW FUNCTIONALITY IN
-##WIKIPEDIA.PY.  It is being retained solely for compatibility in case any
-##custom-written bots rely upon it.  Bot authors should replace any uses
-##of this module as follows:
-##
-##    OLD:    mediawiki_messages.get(key, site)
-##    NEW:    site.mediawiki_message(key)
-##
-##    OLD:    mediawiki_messages.has(key, site)
-##    NEW:    site.has_mediawiki_message(key)
-##
-##    OLD:    mediawiki_messages.makepath(path)
-##    NEW:    wikipedia.makepath(path)
-##
-##########################################################################
-
-import warnings
-warnings.warn(
-"""The mediawiki_messages module is deprecated and no longer
-maintained; see the source code for new methods to replace
-calls to this module.""",
-            DeprecationWarning, stacklevel=2)
-
-
-import wikipedia
-import re, sys, pickle
-import os.path
-import time
-import codecs
-import urllib
-from BeautifulSoup import *
-
-__version__='$Id: mediawiki_messages.py 3731 2007-06-20 14:42:55Z russblau $'
-
-loaded = {}
-
-def get(key, site = None, allowreload = True):
-    site = site or wikipedia.getSite()
-    if loaded.has_key(site):
-        # Use cached copy if it exists.
-        dictionary = loaded[site]
-    else:
-        fn = 'mediawiki-messages/mediawiki-messages-%s-%s.dat' % (site.family.name, site.lang)
-        try:
-            # find out how old our saved dump is (in seconds)
-            file_age = time.time() - os.path.getmtime(fn)
-            # if it's older than 1 month, reload it
-            if file_age > 30 * 24 * 60 * 60:
-                print 'Current MediaWiki message dump is one month old, reloading'
-                refresh_messages(site)
-        except OSError:
-            # no saved dumped exists yet
-            refresh_messages(site)
-        f = open(fn, 'r')
-        dictionary = pickle.load(f)
-        f.close()
-        loaded[site] = dictionary
-    key = key[0].lower() + key[1:]
-    if dictionary.has_key(key):
-        return dictionary[key]
-    elif allowreload:
-        refresh_messages(site = site)
-        return get(key, site = site, allowreload = False)
-    else:
-        raise KeyError('MediaWiki Key %s not found' % key)
-
-def has(key, site = None, allowreload = True):
-    try:
-        get(key, site, allowreload)
-        return True
-    except KeyError:
-        return False
-
-def makepath(path):
-    """ creates missing directories for the given path and
-        returns a normalized absolute version of the path.
-
-    - if the given path already exists in the filesystem
-      the filesystem is not modified.
-
-    - otherwise makepath creates directories along the given path
-      using the dirname() of the path. You may append
-      a '/' to the path if you want it to be a directory path.
-
-    from holger at trillke.net 2002/03/18
-    """
-    from os import makedirs
-    from os.path import normpath,dirname,exists,abspath
-
-    dpath = normpath(dirname(path))
-    if not exists(dpath): makedirs(dpath)
-    return normpath(abspath(path))
-    
-def refresh_messages(site = None):
-    site = site or wikipedia.getSite()
-    # get 'all messages' special page's path
-    path = site.allmessages_address()
-    print 'Retrieving MediaWiki messages for %s' % repr(site)
-    wikipedia.put_throttle() # It actually is a get, but a heavy one.
-    allmessages = site.getUrl(path)
-
-    print 'Parsing MediaWiki messages'
-    soup = BeautifulSoup(allmessages,
-                         convertEntities=BeautifulSoup.HTML_ENTITIES)
-    # The MediaWiki namespace in URL-encoded format, as it can contain
-    # non-ASCII characters and spaces.
-    quotedMwNs = urllib.quote(site.namespace(8).replace(' ', '_').encode(site.encoding()))
-    mw_url = site.path() + "?title=" + quotedMwNs + ":"
-    altmw_url = site.path() + "/" + quotedMwNs + ":"
-    nicemw_url = site.nice_get_address(quotedMwNs + ":")
-    shortmw_url = "/" + quotedMwNs + ":"
-    ismediawiki = lambda url:url and (url.startswith(mw_url)
-                                      or url.startswith(altmw_url)
-                                      or url.startswith(nicemw_url)
-                                      or url.startswith(shortmw_url))
-    # we will save the found key:value pairs here
-    dictionary = {}
-
-    try:
-        for keytag in soup('a', href=ismediawiki):
-            # Key strings only contain ASCII characters, so we can save them as
-            # strs
-            key = str(keytag.find(text=True))
-            keyrow = keytag.parent.parent
-            if keyrow['class'] == "orig":
-                valrow = keyrow.findNextSibling('tr')
-                assert valrow['class'] == "new"
-                value = unicode(valrow.td.string).strip()
-            elif keyrow['class'] == 'def':
-                value = unicode(keyrow('td')[1].string).strip()
-            else:
-                raise AssertionError("Unknown tr class value: %s" % keyrow['class'])
-            dictionary[key] = value
-    except Exception, e:
-        wikipedia.debugDump( 'MediaWiki_Msg', site, u'%s: %s while processing URL: %s' % (repr(e), str(e), unicode(path)), allmessages)
-        raise
-
-    # Save the dictionary to disk
-    # The file is stored in the mediawiki_messages subdir. Create if necessary. 
-    if dictionary == {}:
-        wikipedia.debugDump( 'MediaWiki_Msg', site, u'Error URL: '+unicode(path), allmessages )
-        sys.exit()
-    else:
-        f = open(makepath('mediawiki-messages/mediawiki-messages-%s-%s.dat' % (site.family.name, site.lang)), 'w')
-        pickle.dump(dictionary, f)
-        f.close()
-    print "Loaded %i values from %s" % (len(dictionary.keys()), site)
-    #print dictionary['sitestatstext']
-
-def refresh_all_messages():
-    import dircache, time
-    filenames = dircache.listdir('mediawiki-messages')
-    message_filenameR = re.compile('mediawiki-messages-([a-z:]+)-([a-z:]+).dat')
-    for filename in filenames:
-        match = message_filenameR.match(filename)
-        if match:
-            family = match.group(1)
-            lang = match.group(2)
-            site = wikipedia.getSite(code = lang, fam = family)
-            refresh_messages(site)
-
-def main():
-    refresh_all = False
-    refresh = False
-    key = None
-    for arg in wikipedia.handleArgs():
-        if arg == '-all':
-            refresh_all = True
-        elif arg == '-refresh':
-            refresh = True
-        else:
-            key = arg
-    if key:
-        wikipedia.output(get(key), toStdout = True)
-    elif refresh_all:
-        refresh_all_messages()
-    elif refresh:
-        refresh_messages(wikipedia.getSite())
-    else:
-        wikipedia.showHelp('mediawiki_messages')
-
-if __name__ == "__main__":
-    try:
-        main()
-    except:
-        wikipedia.stopme()
-        raise
-    else:
-        wikipedia.stopme()
-
+# -*- coding: utf-8 -*-
+"""
+Allows access to the MediaWiki messages, that's the label texts of the MediaWiki
+software in the current language. These can be used in other bots.
+
+The function refresh_messages() downloads all the current messages and saves
+them to disk. It is run automatically when a bot first tries to access one of
+the messages. It can be updated manually by running this script, e.g. when
+somebody changed the current message at the wiki. The texts will also be
+reloaded automatically once a month.
+
+Syntax: python mediawiki_messages [-all]
+
+Command line options:
+    -refresh - Reloads messages for the home wiki or for the one defined via
+               the -lang and -family parameters.
+
+    -all     - Reloads messages for all wikis where messages are already present
+
+    If another parameter is given, it will be interpreted as a MediaWiki key.
+    The script will then output the respective value, without refreshing..
+    
+"""
+
+# (C) Daniel Herding, 2004
+#
+# Distributed under the terms of the MIT license.
+
+##THIS MODULE IS DEPRECATED AND HAS BEEN REPLACED BY NEW FUNCTIONALITY IN
+##WIKIPEDIA.PY.  It is being retained solely for compatibility in case any
+##custom-written bots rely upon it.  Bot authors should replace any uses
+##of this module as follows:
+##
+##    OLD:    mediawiki_messages.get(key, site)
+##    NEW:    site.mediawiki_message(key)
+##
+##    OLD:    mediawiki_messages.has(key, site)
+##    NEW:    site.has_mediawiki_message(key)
+##
+##    OLD:    mediawiki_messages.makepath(path)
+##    NEW:    wikipedia.makepath(path)
+##
+##########################################################################
+
+import warnings
+warnings.warn(
+"""The mediawiki_messages module is deprecated and no longer
+maintained; see the source code for new methods to replace
+calls to this module.""",
+            DeprecationWarning, stacklevel=2)
+
+
+import wikipedia
+import re, sys, pickle
+import os.path
+import time
+import codecs
+import urllib
+from BeautifulSoup import *
+
+__version__='$Id: mediawiki_messages.py 3731 2007-06-20 14:42:55Z russblau $'
+
+loaded = {}
+
+def get(key, site = None, allowreload = True):
+    site = site or wikipedia.getSite()
+    if loaded.has_key(site):
+        # Use cached copy if it exists.
+        dictionary = loaded[site]
+    else:
+        fn = 'mediawiki-messages/mediawiki-messages-%s-%s.dat' % (site.family.name, site.lang)
+        try:
+            # find out how old our saved dump is (in seconds)
+            file_age = time.time() - os.path.getmtime(fn)
+            # if it's older than 1 month, reload it
+            if file_age > 30 * 24 * 60 * 60:
+                print 'Current MediaWiki message dump is one month old, reloading'
+                refresh_messages(site)
+        except OSError:
+            # no saved dumped exists yet
+            refresh_messages(site)
+        f = open(fn, 'r')
+        dictionary = pickle.load(f)
+        f.close()
+        loaded[site] = dictionary
+    key = key[0].lower() + key[1:]
+    if dictionary.has_key(key):
+        return dictionary[key]
+    elif allowreload:
+        refresh_messages(site = site)
+        return get(key, site = site, allowreload = False)
+    else:
+        raise KeyError('MediaWiki Key %s not found' % key)
+
+def has(key, site = None, allowreload = True):
+    try:
+        get(key, site, allowreload)
+        return True
+    except KeyError:
+        return False
+
+def makepath(path):
+    """ creates missing directories for the given path and
+        returns a normalized absolute version of the path.
+
+    - if the given path already exists in the filesystem
+      the filesystem is not modified.
+
+    - otherwise makepath creates directories along the given path
+      using the dirname() of the path. You may append
+      a '/' to the path if you want it to be a directory path.
+
+    from holger at trillke.net 2002/03/18
+    """
+    from os import makedirs
+    from os.path import normpath,dirname,exists,abspath
+
+    dpath = normpath(dirname(path))
+    if not exists(dpath): makedirs(dpath)
+    return normpath(abspath(path))
+    
+def refresh_messages(site = None):
+    site = site or wikipedia.getSite()
+    # get 'all messages' special page's path
+    path = site.allmessages_address()
+    print 'Retrieving MediaWiki messages for %s' % repr(site)
+    wikipedia.put_throttle() # It actually is a get, but a heavy one.
+    allmessages = site.getUrl(path)
+
+    print 'Parsing MediaWiki messages'
+    soup = BeautifulSoup(allmessages,
+                         convertEntities=BeautifulSoup.HTML_ENTITIES)
+    # The MediaWiki namespace in URL-encoded format, as it can contain
+    # non-ASCII characters and spaces.
+    quotedMwNs = urllib.quote(site.namespace(8).replace(' ', '_').encode(site.encoding()))
+    mw_url = site.path() + "?title=" + quotedMwNs + ":"
+    altmw_url = site.path() + "/" + quotedMwNs + ":"
+    nicemw_url = site.nice_get_address(quotedMwNs + ":")
+    shortmw_url = "/" + quotedMwNs + ":"
+    ismediawiki = lambda url:url and (url.startswith(mw_url)
+                                      or url.startswith(altmw_url)
+                                      or url.startswith(nicemw_url)
+                                      or url.startswith(shortmw_url))
+    # we will save the found key:value pairs here
+    dictionary = {}
+
+    try:
+        for keytag in soup('a', href=ismediawiki):
+            # Key strings only contain ASCII characters, so we can save them as
+            # strs
+            key = str(keytag.find(text=True))
+            keyrow = keytag.parent.parent
+            if keyrow['class'] == "orig":
+                valrow = keyrow.findNextSibling('tr')
+                assert valrow['class'] == "new"
+                value = unicode(valrow.td.string).strip()
+            elif keyrow['class'] == 'def':
+                value = unicode(keyrow('td')[1].string).strip()
+            else:
+                raise AssertionError("Unknown tr class value: %s" % keyrow['class'])
+            dictionary[key] = value
+    except Exception, e:
+        wikipedia.debugDump( 'MediaWiki_Msg', site, u'%s: %s while processing URL: %s' % (repr(e), str(e), unicode(path)), allmessages)
+        raise
+
+    # Save the dictionary to disk
+    # The file is stored in the mediawiki_messages subdir. Create if necessary. 
+    if dictionary == {}:
+        wikipedia.debugDump( 'MediaWiki_Msg', site, u'Error URL: '+unicode(path), allmessages )
+        sys.exit()
+    else:
+        f = open(makepath('mediawiki-messages/mediawiki-messages-%s-%s.dat' % (site.family.name, site.lang)), 'w')
+        pickle.dump(dictionary, f)
+        f.close()
+    print "Loaded %i values from %s" % (len(dictionary.keys()), site)
+    #print dictionary['sitestatstext']
+
+def refresh_all_messages():
+    import dircache, time
+    filenames = dircache.listdir('mediawiki-messages')
+    message_filenameR = re.compile('mediawiki-messages-([a-z:]+)-([a-z:]+).dat')
+    for filename in filenames:
+        match = message_filenameR.match(filename)
+        if match:
+            family = match.group(1)
+            lang = match.group(2)
+            site = wikipedia.getSite(code = lang, fam = family)
+            refresh_messages(site)
+
+def main():
+    refresh_all = False
+    refresh = False
+    key = None
+    for arg in wikipedia.handleArgs():
+        if arg == '-all':
+            refresh_all = True
+        elif arg == '-refresh':
+            refresh = True
+        else:
+            key = arg
+    if key:
+        wikipedia.output(get(key), toStdout = True)
+    elif refresh_all:
+        refresh_all_messages()
+    elif refresh:
+        refresh_messages(wikipedia.getSite())
+    else:
+        wikipedia.showHelp('mediawiki_messages')
+
+if __name__ == "__main__":
+    try:
+        main()
+    except:
+        wikipedia.stopme()
+        raise
+    else:
+        wikipedia.stopme()
+


Property changes on: trunk/pywikipedia/archive/mediawiki_messages.py
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/pywikipedia/category_redirect.py
===================================================================
--- trunk/pywikipedia/category_redirect.py	2008-07-05 12:57:13 UTC (rev 5674)
+++ trunk/pywikipedia/category_redirect.py	2008-07-05 18:21:03 UTC (rev 5675)
@@ -1,71 +1,71 @@
-#!/usr/bin/python
-# -*- coding: utf-8  -*-
-"""
-Script to clean up http://commons.wikimedia.org/wiki/Category:Non-empty_category_redirects
-
-Moves all images, pages and categories in redirect categories to the target category.
-
-"""
-
-#
-# (C) Multichill, 2008
-#
-# Distributed under the terms of the MIT license.
-#
-
-import wikipedia, config, catlib
-from category import *
-
-redirect_templates = [u'Category redirect', u'Categoryredirect', u'See cat', u'Seecat', u'Catredirect', u'Cat redirect', u'CatRed', u'Catredir']
-move_message = u'Moving from [[%s|%s]] to [[%s|%s]] (following [[Template:Category redirect|category redirect]])'
-
-def get_redirect_cat(category=None):
-    '''
-    Return the target category
-    '''
-    destination = None
-    site = wikipedia.getSite(u'commons', u'commons')
-    for template in category.templatesWithParams():
-        if ((template[0] in redirect_templates) and (len(template[1]) > 0)):
-            #destination = template[1][0];
-            destination =catlib.Category(site, template[1][0])
-            if not destination.exists():
-                return None
-    return destination
-    
-
-def main():
-    '''
-    Main loop. Loop over all categories of Category:Non-empty_category_redirects and move all content.
-    '''    
-
-    site = wikipedia.getSite(u'commons', u'commons')
-    dirtycat = catlib.Category(site, u'Category:Non-empty category redirects')
-    destination = None
-    catbot = None
-    
-    for old_category in dirtycat.subcategories():
-        destination = get_redirect_cat(old_category)
-        if destination:
-            wikipedia.output(destination.title())
-            for page in old_category.articles():
-                try:                                
-                    catlib.change_category(page, old_category, destination, move_message % (old_category.title(), old_category.titleWithoutNamespace(), destination.title(), destination.titleWithoutNamespace()))
-                except wikipedia.IsRedirectPage:
-                    wikipedia.output(page.title() + u' is a redirect!')
-            for cat in old_category.subcategories():
-                try:                
-                    catlib.change_category(cat, old_category, destination, move_message % (old_category.title(), old_category.titleWithoutNamespace(), destination.title(), destination.titleWithoutNamespace()))
-                except wikipedia.IsRedirectPage:
-                    wikipedia.output(page.title() + u' is a redirect!')
-        #Dummy edit to refresh the page, shouldnt show up in any logs.
-        try:
-            old_category.put(old_category.get())
-        except:
-            wikipedia.output(u'Dummy edit at ' + old_category.title() + u' failed')        
-
-if __name__ == "__main__":
-    try:
-        main()
-    finally:
-        wikipedia.stopme()
+#!/usr/bin/python
+# -*- coding: utf-8  -*-
+"""
+Script to clean up http://commons.wikimedia.org/wiki/Category:Non-empty_category_redirects
+
+Moves all images, pages and categories in redirect categories to the target category.
+
+"""
+
+#
+# (C) Multichill, 2008
+#
+# Distributed under the terms of the MIT license.
+#
+
+import wikipedia, config, catlib
+from category import *
+
+redirect_templates = [u'Category redirect', u'Categoryredirect', u'See cat', u'Seecat', u'Catredirect', u'Cat redirect', u'CatRed', u'Catredir']
+move_message = u'Moving from [[%s|%s]] to [[%s|%s]] (following [[Template:Category redirect|category redirect]])'
+
+def get_redirect_cat(category=None):
+    '''
+    Return the target category
+    '''
+    destination = None
+    site = wikipedia.getSite(u'commons', u'commons')
+    for template in category.templatesWithParams():
+        if ((template[0] in redirect_templates) and (len(template[1]) > 0)):
+            #destination = template[1][0];
+            destination =catlib.Category(site, template[1][0])
+            if not destination.exists():
+                return None
+    return destination
+    
+
+def main():
+    '''
+    Main loop. Loop over all categories of Category:Non-empty_category_redirects and move all content.
+    '''    
+
+    site = wikipedia.getSite(u'commons', u'commons')
+    dirtycat = catlib.Category(site, u'Category:Non-empty category redirects')
+    destination = None
+    catbot = None
+    
+    for old_category in dirtycat.subcategories():
+        destination = get_redirect_cat(old_category)
+        if destination:
+            wikipedia.output(destination.title())
+            for page in old_category.articles():
+                try:                                
+                    catlib.change_category(page, old_category, destination, move_message % (old_category.title(), old_category.titleWithoutNamespace(), destination.title(), destination.titleWithoutNamespace()))
+                except wikipedia.IsRedirectPage:
+                    wikipedia.output(page.title() + u' is a redirect!')
+            for cat in old_category.subcategories():
+                try:                
+                    catlib.change_category(cat, old_category, destination, move_message % (old_category.title(), old_category.titleWithoutNamespace(), destination.title(), destination.titleWithoutNamespace()))
+                except wikipedia.IsRedirectPage:
+                    wikipedia.output(page.title() + u' is a redirect!')
+        #Dummy edit to refresh the page, shouldnt show up in any logs.
+        try:
+            old_category.put(old_category.get())
+        except:
+            wikipedia.output(u'Dummy edit at ' + old_category.title() + u' failed')        
+
+if __name__ == "__main__":
+    try:
+        main()
+    finally:
+        wikipedia.stopme()


Property changes on: trunk/pywikipedia/category_redirect.py
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/pywikipedia/commonsdelinker/plugins.txt
===================================================================
--- trunk/pywikipedia/commonsdelinker/plugins.txt	2008-07-05 12:57:13 UTC (rev 5674)
+++ trunk/pywikipedia/commonsdelinker/plugins.txt	2008-07-05 18:21:03 UTC (rev 5675)
@@ -1,53 +1,53 @@
-CommonsDelinker supports a plugin system, which allows modifying the delink and
-replace parameters on a case by case basis. 
-
-Plugins should be registered in the configuration file. CommonsDelinker expects
-the configuration value CommonsDelinker['plugins'] to be an iterable object.
-The items of this iterable should be module.object strings of the plugin. The 
-plugin is expected to reside as module.py in commonsdelinker/plugins. The
-object should exist and should be a callable object or type with an attribute 
-'hook' being a string indicating the hook name.
-
-Some parameters are modyfiable by the plugin. Those include the mutable objects
-and some immutable object wrapped in an ImmutableByReference object. The value
-of such an object can be get/set by the get and set method. Modyfiable 
-parameters are preceded by an ampersand & in this documentation.
-
-A hook that gives False as return value will terminate the hook chain and for
-most hooks also terminate the caller.
-
-== List of hooks and their parameters ==
-
-before_delink(image, usage, timestamp, admin, reason, replacement)
-  Called once per image. Returing False will cancel delinking this image.
-
-simple_replace(page, summary, image, &replacement, match, groups)
-gallery_replace(page, summary, image, &replacement, match, groups)
-complex_replace(page, summary, image, &replacement, match, groups)
-  Called each time an occerence is to be replaced. Returning False will not 
-  replace this occerence.
-
-before_save(page, text, &new_text, &summary)
-  Called before the page is saved. Returning False will not save the page.
-
-after_delink(image, usage, timestamp, admin, reason, replacement)
-  Called once per image after delink.
-
-== Example ==
-# Saves a diff for every delink.
-import difflib
-
-class Diff(object):
-	hook = 'before_save'
-	def __init__(self, CommonsDelinker):
-		self.CommonsDelinker = CommonsDelinker
-	def __call__(self, page, text, new_text, summary):
-		diff = difflib.context_diff(
-			text.encode('utf-8').splitlines(True),
-			new_text.get().encode('utf-8').splitlines(True))
-			
-		f = open((u'diff/%s-%s-%s.txt' % (page.urlname().replace('/', '-'),
-			page.site().dbName(), page.editTime())).encode('utf-8', 'ignore'), 'w')
-						
-		f.writelines(diff)
-		f.close()
\ No newline at end of file
+CommonsDelinker supports a plugin system, which allows modifying the delink and
+replace parameters on a case by case basis.
+
+Plugins should be registered in the configuration file. CommonsDelinker expects
+the configuration value CommonsDelinker['plugins'] to be an iterable object.
+The items of this iterable should be module.object strings of the plugin. The
+plugin is expected to reside as module.py in commonsdelinker/plugins. The
+object should exist and should be a callable object or type with an attribute
+'hook' being a string indicating the hook name.
+
+Some parameters are modyfiable by the plugin. Those include the mutable objects
+and some immutable object wrapped in an ImmutableByReference object. The value
+of such an object can be get/set by the get and set method. Modyfiable
+parameters are preceded by an ampersand & in this documentation.
+
+A hook that gives False as return value will terminate the hook chain and for
+most hooks also terminate the caller.
+
+== List of hooks and their parameters ==
+
+before_delink(image, usage, timestamp, admin, reason, replacement)
+  Called once per image. Returing False will cancel delinking this image.
+
+simple_replace(page, summary, image, &replacement, match, groups)
+gallery_replace(page, summary, image, &replacement, match, groups)
+complex_replace(page, summary, image, &replacement, match, groups)
+  Called each time an occerence is to be replaced. Returning False will not
+  replace this occerence.
+
+before_save(page, text, &new_text, &summary)
+  Called before the page is saved. Returning False will not save the page.
+
+after_delink(image, usage, timestamp, admin, reason, replacement)
+  Called once per image after delink.
+
+== Example ==
+# Saves a diff for every delink.
+import difflib
+
+class Diff(object):
+	hook = 'before_save'
+	def __init__(self, CommonsDelinker):
+		self.CommonsDelinker = CommonsDelinker
+	def __call__(self, page, text, new_text, summary):
+		diff = difflib.context_diff(
+			text.encode('utf-8').splitlines(True),
+			new_text.get().encode('utf-8').splitlines(True))
+
+		f = open((u'diff/%s-%s-%s.txt' % (page.urlname().replace('/', '-'),
+			page.site().dbName(), page.editTime())).encode('utf-8', 'ignore'), 'w')
+
+		f.writelines(diff)
+		f.close()


Property changes on: trunk/pywikipedia/commonsdelinker/plugins.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/pywikipedia/families/README-family.txt
===================================================================
--- trunk/pywikipedia/families/README-family.txt	2008-07-05 12:57:13 UTC (rev 5674)
+++ trunk/pywikipedia/families/README-family.txt	2008-07-05 18:21:03 UTC (rev 5675)
@@ -1,183 +1,183 @@
-How to create a new family file to add a new wiki to the bot framework.
-
-(c) 2008, the Pywikipediabot team
-
-Copy and paste the text below "COPY HERE" into your favorite text editor, and
-save it as WIKINAME_family.py in the families/ subdirectory.  Replace
-WIKINAME with the name you want to use for the new wiki family, making sure
-that it doesn't duplicate any existing name.
-
-A "family" is any group of wikis located on the same server; usually they
-are versions of the same type of content in different languages, but this
-isn't required.  A family can consist of just one wiki, or more; if there is
-more than one wiki, each wiki needs to be identified by a unique code.
-
-After you copy the text, go through and edit it, based upon the comment
-lines.  First, do a global search-and-replace to change all instances of
-'WIKINAME' to your actual wiki name.  Everything in the example below is
-based on the bot's default settings, except for the namespace names, which
-are made-up examples. You only need to change it if your wiki's value is
-different from the default. You can delete anything that is not indicated as
-"REQUIRED", if your new wiki doesn't vary from the default settings.
-
-== COPY HERE ==
-
-# -*- coding: utf-8  -*-              # REQUIRED
-import config, family, urllib         # REQUIRED
-
-class Family(family.Family):          # REQUIRED
-    def __init__(self):               # REQUIRED
-        family.Family.__init__(self)  # REQUIRED
-        self.name = 'WIKINAME'        # REQUIRED; replace with actual name
-
-        self.langs = {                # REQUIRED
-            'en': 'www.example.com',  # Include one line for each wiki in family
-            'fr': 'www.example.fr',   # in the format 'code': 'hostname',
-        }
-
-        # Translation used on all wikis for the different namespaces.
-        # Most namespaces are inherited from family.Family.
-        # Check the family.py file (in main directory) to see the standard
-        # namespace translations for each known language.
-
-        # You only need to enter translations that differ from the default.
-        # There are two ways of entering namespace translations.
-        # 1.  If you only need to change the translation of a particular
-        #     namespace for one or two languages, use this format:
-        self.namespaces[2]['en'] = u'Wikiuser'
-        self.namespaces[3]['en'] = u'Wikiuser talk'
-
-        # 2.  If you need to change the translation for many languages
-        #     for the same namespace number, use this format (this is common
-        #     for namespaces 4 and 5, because these are usually given a
-        #     unique name for each wiki):
-        self.namespaces[4] = {
-            '_default': [u'WIKINAME', self.namespaces[4]['_default']], # REQUIRED
-            'de': 'Name des wiki',
-            'es': 'Nombre del wiki',
-            'fr': 'Nom du wiki',
-            # ETC.
-        }
-        
-        # Wikimedia wikis all use "bodyContent" as the id of the <div>
-        # element that contains the actual page content; change this for
-        # wikis that use something else (e.g., mozilla family)
-        self.content_id = "bodyContent"
-
-        # On most wikis page names must start with a capital letter, but some
-        # languages don't use this.  This should be a list of languages that
-        # _don't_ require the first letter to be capitalized; e.g.,
-        # self.nocapitalize = ['foo', 'bar']
-        self.nocapitalize = []
-
-        # SETTINGS FOR WIKIS THAT USE DISAMBIGUATION PAGES:
-        
-        # A list of disambiguation template names in different languages
-        self.disambiguationTemplates = {
-            'en': ['disambig', 'disambiguation'],
-        }
-
-        # A list with the name of the category containing disambiguation
-        # pages for the various languages. Only one category per language,
-        # and without the namespace, so add things like:
-        self.disambcatname = {
-            'en': "Disambiguation",
-        }
-
-        # SETTINGS FOR WIKIS THAT USE INTERLANGUAGE LINKS:
-        
-        # attop is a list of languages that prefer to have the interwiki
-        # links at the top of the page.
-        self.interwiki_attop = []
-
-        # on_one_line is a list of languages that want the interwiki links
-        # one-after-another on a single line
-        self.interwiki_on_one_line = []
-
-        # String used as separator between interwiki links and the text
-        self.interwiki_text_separator = '\r\n\r\n'
-
-        # Which languages have a special order for putting interlanguage links,
-        # and what order is it? If a language is not in interwiki_putfirst,
-        # alphabetical order on language code is used. For languages that are in
-        # interwiki_putfirst, interwiki_putfirst is checked first, and
-        # languages are put in the order given there. All other languages are put
-        # after those, in code-alphabetical order.
-        self.interwiki_putfirst = {}
-
-        # Languages in interwiki_putfirst_doubled should have a number plus a list
-        # of languages. If there are at least the number of interwiki links, all
-        # languages in the list should be placed at the front as well as in the
-        # normal list.
-        self.interwiki_putfirst_doubled = {}
-
-        # Some families, e. g. commons and meta, are not multilingual and
-        # forward interlanguage links to another family (wikipedia).
-        # These families can set this variable to the name of the target
-        # family.
-        self.interwiki_forward = None
-
-        # Which language codes no longer exist and by which language code
-        # should they be replaced. If for example the language with code xx:
-        # has been replaced by code yy:, add {'xx':'yy'} to obsolete.
-        # If all links to language xx: should be removed, add {'xx': None}.
-        self.obsolete = {}
-
-        # SETTINGS FOR CATEGORY LINKS:
-        
-        # Languages that want the category links at the top of the page
-        self.category_attop = []
-        
-        # languages that want the category links
-        # one-after-another on a single line
-        self.category_on_one_line = []
-
-        # String used as separator between category links and the text
-        self.category_text_separator = '\r\n\r\n'
-
-        # When both at the bottom should categories come after interwikilinks?
-        self.categories_last = []
-
-        # SETTINGS FOR LDAP AUTHENTICATION
-        # If your wiki uses:
-        #  http://www.mediawiki.org/wiki/Extension:LDAP_Authentication.
-        # then uncomment this line and define the user's domain required
-        # at login.
-        #self.name = 'domain here'
-
-    def protocol(self, code):
-        """
-        Can be overridden to return 'https'. Other protocols are not supported.
-        """
-        return 'http'
-
-    def scriptpath(self, code):
-        """The prefix used to locate scripts on this wiki.
-
-        This is the value displayed when you enter {{SCRIPTPATH}} on a
-        wiki page (often displayed at [[Help:Variables]] if the wiki has
-        copied the master help page correctly).
-
-        The default value is the one used on Wikimedia Foundation wikis,
-        but needs to be overridden in the family file for any wiki that
-        uses a different value.
-
-        """
-        return '/w'
-
-    # IMPORTANT: if your wiki does not support the api.php interface,
-    # you must uncomment the second line of this method:
-    def apipath(self, code):
-        # raise NotImplementedError, "%s wiki family does not support api.php" % self.name
-        return '%s/api.php' % self.scriptpath(code)
-
-    # Which version of MediaWiki is used?
-    def version(self, code):
-        # Replace with the actual version being run on your wiki
-        return '1.13alpha'
-
-    def code2encoding(self, code):
-        """Return the encoding for a specific language wiki"""
-        # Most wikis nowadays use UTF-8, but change this if yours uses
-        # a different encoding
-        return 'utf-8'
+How to create a new family file to add a new wiki to the bot framework.
+
+(c) 2008, the Pywikipediabot team
+
+Copy and paste the text below "COPY HERE" into your favorite text editor, and
+save it as WIKINAME_family.py in the families/ subdirectory.  Replace
+WIKINAME with the name you want to use for the new wiki family, making sure
+that it doesn't duplicate any existing name.
+
+A "family" is any group of wikis located on the same server; usually they
+are versions of the same type of content in different languages, but this
+isn't required.  A family can consist of just one wiki, or more; if there is
+more than one wiki, each wiki needs to be identified by a unique code.
+
+After you copy the text, go through and edit it, based upon the comment
+lines.  First, do a global search-and-replace to change all instances of
+'WIKINAME' to your actual wiki name.  Everything in the example below is
+based on the bot's default settings, except for the namespace names, which
+are made-up examples. You only need to change it if your wiki's value is
+different from the default. You can delete anything that is not indicated as
+"REQUIRED", if your new wiki doesn't vary from the default settings.
+
+== COPY HERE ==
+
+# -*- coding: utf-8  -*-              # REQUIRED
+import config, family, urllib         # REQUIRED
+
+class Family(family.Family):          # REQUIRED
+    def __init__(self):               # REQUIRED
+        family.Family.__init__(self)  # REQUIRED
+        self.name = 'WIKINAME'        # REQUIRED; replace with actual name
+
+        self.langs = {                # REQUIRED
+            'en': 'www.example.com',  # Include one line for each wiki in family
+            'fr': 'www.example.fr',   # in the format 'code': 'hostname',
+        }
+
+        # Translation used on all wikis for the different namespaces.
+        # Most namespaces are inherited from family.Family.
+        # Check the family.py file (in main directory) to see the standard
+        # namespace translations for each known language.
+
+        # You only need to enter translations that differ from the default.
+        # There are two ways of entering namespace translations.
+        # 1.  If you only need to change the translation of a particular
+        #     namespace for one or two languages, use this format:
+        self.namespaces[2]['en'] = u'Wikiuser'
+        self.namespaces[3]['en'] = u'Wikiuser talk'
+
+        # 2.  If you need to change the translation for many languages
+        #     for the same namespace number, use this format (this is common
+        #     for namespaces 4 and 5, because these are usually given a
+        #     unique name for each wiki):
+        self.namespaces[4] = {
+            '_default': [u'WIKINAME', self.namespaces[4]['_default']], # REQUIRED
+            'de': 'Name des wiki',
+            'es': 'Nombre del wiki',
+            'fr': 'Nom du wiki',
+            # ETC.
+        }
+
+        # Wikimedia wikis all use "bodyContent" as the id of the <div>
+        # element that contains the actual page content; change this for
+        # wikis that use something else (e.g., mozilla family)
+        self.content_id = "bodyContent"
+
+        # On most wikis page names must start with a capital letter, but some
+        # languages don't use this.  This should be a list of languages that
+        # _don't_ require the first letter to be capitalized; e.g.,
+        # self.nocapitalize = ['foo', 'bar']
+        self.nocapitalize = []
+
+        # SETTINGS FOR WIKIS THAT USE DISAMBIGUATION PAGES:
+
+        # A list of disambiguation template names in different languages
+        self.disambiguationTemplates = {
+            'en': ['disambig', 'disambiguation'],
+        }
+
+        # A list with the name of the category containing disambiguation
+        # pages for the various languages. Only one category per language,
+        # and without the namespace, so add things like:
+        self.disambcatname = {
+            'en': "Disambiguation",
+        }
+
+        # SETTINGS FOR WIKIS THAT USE INTERLANGUAGE LINKS:
+
+        # attop is a list of languages that prefer to have the interwiki
+        # links at the top of the page.
+        self.interwiki_attop = []
+
+        # on_one_line is a list of languages that want the interwiki links
+        # one-after-another on a single line
+        self.interwiki_on_one_line = []
+
+        # String used as separator between interwiki links and the text
+        self.interwiki_text_separator = '\r\n\r\n'
+
+        # Which languages have a special order for putting interlanguage links,
+        # and what order is it? If a language is not in interwiki_putfirst,
+        # alphabetical order on language code is used. For languages that are in
+        # interwiki_putfirst, interwiki_putfirst is checked first, and
+        # languages are put in the order given there. All other languages are put
+        # after those, in code-alphabetical order.
+        self.interwiki_putfirst = {}
+
+        # Languages in interwiki_putfirst_doubled should have a number plus a list
+        # of languages. If there are at least the number of interwiki links, all
+        # languages in the list should be placed at the front as well as in the
+        # normal list.
+        self.interwiki_putfirst_doubled = {}
+
+        # Some families, e. g. commons and meta, are not multilingual and
+        # forward interlanguage links to another family (wikipedia).
+        # These families can set this variable to the name of the target
+        # family.
+        self.interwiki_forward = None
+
+        # Which language codes no longer exist and by which language code
+        # should they be replaced. If for example the language with code xx:
+        # has been replaced by code yy:, add {'xx':'yy'} to obsolete.
+        # If all links to language xx: should be removed, add {'xx': None}.
+        self.obsolete = {}
+
+        # SETTINGS FOR CATEGORY LINKS:
+
+        # Languages that want the category links at the top of the page
+        self.category_attop = []
+
+        # languages that want the category links
+        # one-after-another on a single line
+        self.category_on_one_line = []
+
+        # String used as separator between category links and the text
+        self.category_text_separator = '\r\n\r\n'
+
+        # When both at the bottom should categories come after interwikilinks?
+        self.categories_last = []
+
+        # SETTINGS FOR LDAP AUTHENTICATION
+        # If your wiki uses:
+        #  http://www.mediawiki.org/wiki/Extension:LDAP_Authentication.
+        # then uncomment this line and define the user's domain required
+        # at login.
+        #self.name = 'domain here'
+
+    def protocol(self, code):
+        """
+        Can be overridden to return 'https'. Other protocols are not supported.
+        """
+        return 'http'
+
+    def scriptpath(self, code):
+        """The prefix used to locate scripts on this wiki.
+
+        This is the value displayed when you enter {{SCRIPTPATH}} on a
+        wiki page (often displayed at [[Help:Variables]] if the wiki has
+        copied the master help page correctly).
+
+        The default value is the one used on Wikimedia Foundation wikis,
+        but needs to be overridden in the family file for any wiki that
+        uses a different value.
+
+        """
+        return '/w'
+
+    # IMPORTANT: if your wiki does not support the api.php interface,
+    # you must uncomment the second line of this method:
+    def apipath(self, code):
+        # raise NotImplementedError, "%s wiki family does not support api.php" % self.name
+        return '%s/api.php' % self.scriptpath(code)
+
+    # Which version of MediaWiki is used?
+    def version(self, code):
+        # Replace with the actual version being run on your wiki
+        return '1.13alpha'
+
+    def code2encoding(self, code):
+        """Return the encoding for a specific language wiki"""
+        # Most wikis nowadays use UTF-8, but change this if yours uses
+        # a different encoding
+        return 'utf-8'


Property changes on: trunk/pywikipedia/families/README-family.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/pywikipedia/protect.py
===================================================================
--- trunk/pywikipedia/protect.py	2008-07-05 12:57:13 UTC (rev 5674)
+++ trunk/pywikipedia/protect.py	2008-07-05 18:21:03 UTC (rev 5675)
@@ -1,252 +1,252 @@
-# -*- coding: utf-8 -*-
-"""
-This script can be used to protect and unprotect pages en masse.
-Of course, you will need an admin account on the relevant wiki.
- 
-Syntax: python protect.py OPTION...
- 
-Command line options:
- 
--page:       Protect specified page
--cat:        Protect all pages in the given category.
--nosubcats:  Don't protect pages in the subcategories.
--links:      Protect all pages linked from a given page.
--file:       Protect all pages listed in a text file.
--ref:        Protect all pages referring from a given page.
--images:     Protect all images used on a given page.
--always:     Don't prompt to protect pages, just do it.
--summary:    Supply a custom edit summary.
--unprotect:   Actually unprotect pages instead of protecting
--edit:PROTECTION_LEVEL Set edit protection level to PROTECTION_LEVEL
--move:PROTECTION_LEVEL Set move protection level to PROTECTION_LEVEL
-
-## Without support ##
-## -create:PROTECTION_LEVEL Set move protection level to PROTECTION_LEVEL ##
- 
-Values for PROTECTION_LEVEL are: sysop, autoconfirmed, none.
-If an operation parameter (edit, move or create) is not specified, default
-protection level is 'sysop' (or 'none' if -unprotect).
- 
-Examples:
- 
-Protect everything in the category "To protect" prompting.
-    python protect.py -cat:"To protect" -always
- 
-Unprotect all pages listed in text file "unprotect.txt" without prompting.
-    python protect.py -file:unprotect.txt -unprotect
-"""
- 
-# Written by http://it.wikisource.org/wiki/Utente:Qualc1
-# Created by modifying delete.py
-__version__ = '$Id: delete.py 4946 2008-01-29 14:58:25Z wikipedian $'
- 
-#
-# Distributed under the terms of the MIT license.
-#
- 
-import wikipedia, catlib
-import pagegenerators
- 
-# Summary messages for protecting from a category.
-msg_simple_protect = {
-    'en': u'Bot: Protecting a list of files.',
-    'ar': u'بوت: حماية قائمة من الملفات.',
-    'it': u'Bot: Protezione di una lista di pagine.',
-    'pt': u'Bot: Protegendo uma lista de artigos.',
-}
-msg_protect_category = {
-    'en': u'Robot - Protecting all pages from category %s',
-    'ar': u'روبوت - حماية كل الصفحات من التصنيف %s',
-    'it': u'Bot: Protezione di tutte le pagine nella categoria %s.',
-    'pt': u'Bot: Protegendo todos os artigos da categoria %s',
-}
-msg_protect_links = {
-    'en': u'Robot - Protecting all pages linked from %s',
-    'ar': u'روبوت - حماية كل الصفحات الموصولة من %s',
-    'it': u'Bot: Protezione di tutte le pagine linkate da %s.',
-    'pt': u'Bot: Protegendo todos os artigos ligados a %s',
-}
-msg_protect_ref = {
-    'en': u'Robot - Protecting all pages referring from %s',
-    'ar': u'روبوت - حماية كل الصفحات الراجعة من %s',
-    'it': u'Bot: Protezione di tutte le pagine con link verso %s.',
-    'pt': u'Bot: Protegendo todos os artigos afluentes a %s',
-}
-msg_protect_images = {
-    'en': u'Robot - Protecting all images on page %s',
-    'ar': u'روبوت - حماية كل الصور في الصفحة %s',
-    'it': u'Bot: Protezione di tutte le immagini presenti in %s.',
-    'pt': u'Bot: Protegendo todas as imagens do artigo %s',
-}
- 
-class ProtectionRobot:
-    """
-    This robot allows protection of pages en masse.
-    """
- 
-    def __init__(self, generator, summary, always = False, unprotect=False,
-                edit='sysop', move='sysop', create='sysop'):
-        """
-        Arguments:
-            * generator - A page generator.
-            * always - Protect without prompting?
-            * edit, move, create - protection level for these operations
-            * unprotect - unprotect pages (and ignore edit, move, create params)
-        """
-        self.generator = generator
-        self.summary = summary
-        self.always = always
-        self.unprotect = unprotect
-        self.edit = edit
-        self.move = move
- 
-    def run(self):
-        """
-        Starts the robot's action.
-        """
-        #Loop through everything in the page generator and (un)protect it.
-        for page in self.generator:
-            wikipedia.output(u'Processing page %s' % page.title())
-            print self.edit, self.move#, self.create
-            page.protect(unprotect=self.unprotect, reason=self.summary, prompt=self.always,
-                        edit=self.edit, move=self.move)
- 
-# Asks a valid protection level for "operation".
-# Returns the protection level chosen by user.
-def choiceProtectionLevel(operation, default):
-    default = default[0]
-    firstChar = map(lambda level: level[0], protectionLevels)
-    choiceChar = wikipedia.inputChoice('Choice a protection level to %s:' % operation, 
-                            protectionLevels, firstChar, default = default)
-    for level in protectionLevels:
-        if level.startswith(choiceChar):
-            return level
- 
-def main():
-    global protectionLevels
-    protectionLevels = ['sysop', 'autoconfirmed', 'none']
- 
-    pageName = ''
-    summary = ''
-    always = False
-    doSinglePage = False
-    doCategory = False
-    protectSubcategories = True
-    doRef = False
-    doLinks = False
-    doImages = False
-    fileName = ''
-    gen = None
-    edit = ''
-    move = ''
-    defaultProtection = 'sysop'
- 
-    # read command line parameters
-    for arg in wikipedia.handleArgs():
-        if arg == '-always':
-            always = True
-        elif arg.startswith('-file'):
-            if len(arg) == len('-file'):
-                fileName = wikipedia.input(u'Enter name of file to protect pages from:')
-            else:
-                fileName = arg[len('-file:'):]
-        elif arg.startswith('-summary'):
-            if len(arg) == len('-summary'):
-                summary = wikipedia.input(u'Enter a reason for the protection:')
-            else:
-                summary = arg[len('-summary:'):]
-        elif arg.startswith('-cat'):
-            doCategory = True
-            if len(arg) == len('-cat'):
-                pageName = wikipedia.input(u'Enter the category to protect from:')
-            else:
-                pageName = arg[len('-cat:'):]
-        elif arg.startswith('-nosubcats'):
-            protectSubcategories = False
-        elif arg.startswith('-links'):
-            doLinks = True
-            if len(arg) == len('-links'):
-                pageName = wikipedia.input(u'Enter the page to protect from:')
-            else:
-                pageName = arg[len('-links:'):]
-        elif arg.startswith('-ref'):
-            doRef = True
-            if len(arg) == len('-ref'):
-                pageName = wikipedia.input(u'Enter the page to protect from:')
-            else:
-                pageName = arg[len('-ref:'):]
-        elif arg.startswith('-page'):
-            doSinglePage = True
-            if len(arg) == len('-page'):
-                pageName = wikipedia.input(u'Enter the page to protect:')
-            else:
-                pageName = arg[len('-page:'):]
-        elif arg.startswith('-images'):
-            doImages = True
-            if len(arg) == len('-images'):
-                pageName = wikipedia.input(u'Enter the page with the images to protect:')
-            else:
-                pageName = arg[len('-images:'):]
-        elif arg.startswith('-unprotect'):
-            defaultProtection = 'none'
-        elif arg.startswith('-edit'):
-            edit = arg[len('-edit:'):]
-            if edit not in protectionLevels:
-                edit = choiceProtectionLevel('edit', defaultProtection)
-        elif arg.startswith('-move'):
-            move = arg[len('-move:'):]
-            if move not in protectionLevels:
-                move = choiceProtectionLevel('move', defaultProtection)
-        elif arg.startswith('-create'):
-            create = arg[len('-create:'):]
-            if create not in protectionLevels:
-                create = choiceProtectionLevel('create', defaultProtection)
- 
-    mysite = wikipedia.getSite()
- 
-    if doSinglePage:
-        if not summary:
-            summary = wikipedia.input(u'Enter a reason for the protection:')
-        page = wikipedia.Page(mysite, pageName)
-        gen = iter([page])
-    elif doCategory:
-        if not summary:
-            summary = wikipedia.translate(mysite, msg_protect_category) % pageName
-        ns = mysite.category_namespace()
-        categoryPage = catlib.Category(mysite, ns + ':' + pageName)
-        gen = pagegenerators.CategorizedPageGenerator(categoryPage, recurse = protectSubcategories)
-    elif doLinks:
-        if not summary:
-            summary = wikipedia.translate(mysite, msg_protect_links) % pageName
-        linksPage = wikipedia.Page(mysite, pageName)
-        gen = pagegenerators.LinkedPageGenerator(linksPage)
-    elif doRef:
-        if not summary:
-            summary = wikipedia.translate(mysite, msg_protect_ref) % pageName
-        refPage = wikipedia.Page(mysite, pageName)
-        gen = pagegenerators.ReferringPageGenerator(refPage)
-    elif fileName:
-        if not summary:
-            summary = wikipedia.translate(mysite, msg_simple_protect)
-        gen = pagegenerators.TextfilePageGenerator(fileName)
-    elif doImages:
-        if not summary:
-            summary = wikipedia.translate(mysite, msg_protect_images) % pageName
-        gen = pagegenerators.ImagesPageGenerator(wikipedia.Page(mysite, pageName))
- 
-    if gen:
-        wikipedia.setAction(summary)
-        # We are just protecting pages, so we have no need of using a preloading page generator
-        # to actually get the text of those pages.
-        if not edit: edit = defaultProtection
-        if not move: move = defaultProtection
-        bot = ProtectionRobot(gen, summary, always, edit=edit, move=move)
-        bot.run()
-    else:
-        wikipedia.showHelp(u'protect')
- 
-if __name__ == "__main__":
-    try:
-        main()
-    finally:
-        wikipedia.stopme()
+# -*- coding: utf-8 -*-
+"""
+This script can be used to protect and unprotect pages en masse.
+Of course, you will need an admin account on the relevant wiki.
+ 
+Syntax: python protect.py OPTION...
+ 
+Command line options:
+ 
+-page:       Protect specified page
+-cat:        Protect all pages in the given category.
+-nosubcats:  Don't protect pages in the subcategories.
+-links:      Protect all pages linked from a given page.
+-file:       Protect all pages listed in a text file.
+-ref:        Protect all pages referring from a given page.
+-images:     Protect all images used on a given page.
+-always:     Don't prompt to protect pages, just do it.
+-summary:    Supply a custom edit summary.
+-unprotect:   Actually unprotect pages instead of protecting
+-edit:PROTECTION_LEVEL Set edit protection level to PROTECTION_LEVEL
+-move:PROTECTION_LEVEL Set move protection level to PROTECTION_LEVEL
+
+## Without support ##
+## -create:PROTECTION_LEVEL Set move protection level to PROTECTION_LEVEL ##
+ 
+Values for PROTECTION_LEVEL are: sysop, autoconfirmed, none.
+If an operation parameter (edit, move or create) is not specified, default
+protection level is 'sysop' (or 'none' if -unprotect).
+ 
+Examples:
+ 
+Protect everything in the category "To protect" prompting.
+    python protect.py -cat:"To protect" -always
+ 
+Unprotect all pages listed in text file "unprotect.txt" without prompting.
+    python protect.py -file:unprotect.txt -unprotect
+"""
+ 
+# Written by http://it.wikisource.org/wiki/Utente:Qualc1
+# Created by modifying delete.py
+__version__ = '$Id: delete.py 4946 2008-01-29 14:58:25Z wikipedian $'
+ 
+#
+# Distributed under the terms of the MIT license.
+#
+ 
+import wikipedia, catlib
+import pagegenerators
+ 
+# Summary messages for protecting from a category.
+msg_simple_protect = {
+    'en': u'Bot: Protecting a list of files.',
+    'ar': u'بوت: حماية قائمة من الملفات.',
+    'it': u'Bot: Protezione di una lista di pagine.',
+    'pt': u'Bot: Protegendo uma lista de artigos.',
+}
+msg_protect_category = {
+    'en': u'Robot - Protecting all pages from category %s',
+    'ar': u'روبوت - حماية كل الصفحات من التصنيف %s',
+    'it': u'Bot: Protezione di tutte le pagine nella categoria %s.',
+    'pt': u'Bot: Protegendo todos os artigos da categoria %s',
+}
+msg_protect_links = {
+    'en': u'Robot - Protecting all pages linked from %s',
+    'ar': u'روبوت - حماية كل الصفحات الموصولة من %s',
+    'it': u'Bot: Protezione di tutte le pagine linkate da %s.',
+    'pt': u'Bot: Protegendo todos os artigos ligados a %s',
+}
+msg_protect_ref = {
+    'en': u'Robot - Protecting all pages referring from %s',
+    'ar': u'روبوت - حماية كل الصفحات الراجعة من %s',
+    'it': u'Bot: Protezione di tutte le pagine con link verso %s.',
+    'pt': u'Bot: Protegendo todos os artigos afluentes a %s',
+}
+msg_protect_images = {
+    'en': u'Robot - Protecting all images on page %s',
+    'ar': u'روبوت - حماية كل الصور في الصفحة %s',
+    'it': u'Bot: Protezione di tutte le immagini presenti in %s.',
+    'pt': u'Bot: Protegendo todas as imagens do artigo %s',
+}
+ 
+class ProtectionRobot:
+    """
+    This robot allows protection of pages en masse.
+    """
+ 
+    def __init__(self, generator, summary, always = False, unprotect=False,
+                edit='sysop', move='sysop', create='sysop'):
+        """
+        Arguments:
+            * generator - A page generator.
+            * always - Protect without prompting?
+            * edit, move, create - protection level for these operations
+            * unprotect - unprotect pages (and ignore edit, move, create params)
+        """
+        self.generator = generator
+        self.summary = summary
+        self.always = always
+        self.unprotect = unprotect
+        self.edit = edit
+        self.move = move
+ 
+    def run(self):
+        """
+        Starts the robot's action.
+        """
+        #Loop through everything in the page generator and (un)protect it.
+        for page in self.generator:
+            wikipedia.output(u'Processing page %s' % page.title())
+            print self.edit, self.move#, self.create
+            page.protect(unprotect=self.unprotect, reason=self.summary, prompt=self.always,
+                        edit=self.edit, move=self.move)
+ 
+# Asks a valid protection level for "operation".
+# Returns the protection level chosen by user.
+def choiceProtectionLevel(operation, default):
+    default = default[0]
+    firstChar = map(lambda level: level[0], protectionLevels)
+    choiceChar = wikipedia.inputChoice('Choice a protection level to %s:' % operation, 
+                            protectionLevels, firstChar, default = default)
+    for level in protectionLevels:
+        if level.startswith(choiceChar):
+            return level
+ 
+def main():
+    global protectionLevels
+    protectionLevels = ['sysop', 'autoconfirmed', 'none']
+ 
+    pageName = ''
+    summary = ''
+    always = False
+    doSinglePage = False
+    doCategory = False
+    protectSubcategories = True
+    doRef = False
+    doLinks = False
+    doImages = False
+    fileName = ''
+    gen = None
+    edit = ''
+    move = ''
+    defaultProtection = 'sysop'
+ 
+    # read command line parameters
+    for arg in wikipedia.handleArgs():
+        if arg == '-always':
+            always = True
+        elif arg.startswith('-file'):
+            if len(arg) == len('-file'):
+                fileName = wikipedia.input(u'Enter name of file to protect pages from:')
+            else:
+                fileName = arg[len('-file:'):]
+        elif arg.startswith('-summary'):
+            if len(arg) == len('-summary'):
+                summary = wikipedia.input(u'Enter a reason for the protection:')
+            else:
+                summary = arg[len('-summary:'):]
+        elif arg.startswith('-cat'):
+            doCategory = True
+            if len(arg) == len('-cat'):
+                pageName = wikipedia.input(u'Enter the category to protect from:')
+            else:
+                pageName = arg[len('-cat:'):]
+        elif arg.startswith('-nosubcats'):
+            protectSubcategories = False
+        elif arg.startswith('-links'):
+            doLinks = True
+            if len(arg) == len('-links'):
+                pageName = wikipedia.input(u'Enter the page to protect from:')
+            else:
+                pageName = arg[len('-links:'):]
+        elif arg.startswith('-ref'):
+            doRef = True
+            if len(arg) == len('-ref'):
+                pageName = wikipedia.input(u'Enter the page to protect from:')
+            else:
+                pageName = arg[len('-ref:'):]
+        elif arg.startswith('-page'):
+            doSinglePage = True
+            if len(arg) == len('-page'):
+                pageName = wikipedia.input(u'Enter the page to protect:')
+            else:
+                pageName = arg[len('-page:'):]
+        elif arg.startswith('-images'):
+            doImages = True
+            if len(arg) == len('-images'):
+                pageName = wikipedia.input(u'Enter the page with the images to protect:')
+            else:
+                pageName = arg[len('-images:'):]
+        elif arg.startswith('-unprotect'):
+            defaultProtection = 'none'
+        elif arg.startswith('-edit'):
+            edit = arg[len('-edit:'):]
+            if edit not in protectionLevels:
+                edit = choiceProtectionLevel('edit', defaultProtection)
+        elif arg.startswith('-move'):
+            move = arg[len('-move:'):]
+            if move not in protectionLevels:
+                move = choiceProtectionLevel('move', defaultProtection)
+        elif arg.startswith('-create'):
+            create = arg[len('-create:'):]
+            if create not in protectionLevels:
+                create = choiceProtectionLevel('create', defaultProtection)
+ 
+    mysite = wikipedia.getSite()
+ 
+    if doSinglePage:
+        if not summary:
+            summary = wikipedia.input(u'Enter a reason for the protection:')
+        page = wikipedia.Page(mysite, pageName)
+        gen = iter([page])
+    elif doCategory:
+        if not summary:
+            summary = wikipedia.translate(mysite, msg_protect_category) % pageName
+        ns = mysite.category_namespace()
+        categoryPage = catlib.Category(mysite, ns + ':' + pageName)
+        gen = pagegenerators.CategorizedPageGenerator(categoryPage, recurse = protectSubcategories)
+    elif doLinks:
+        if not summary:
+            summary = wikipedia.translate(mysite, msg_protect_links) % pageName
+        linksPage = wikipedia.Page(mysite, pageName)
+        gen = pagegenerators.LinkedPageGenerator(linksPage)
+    elif doRef:
+        if not summary:
+            summary = wikipedia.translate(mysite, msg_protect_ref) % pageName
+        refPage = wikipedia.Page(mysite, pageName)
+        gen = pagegenerators.ReferringPageGenerator(refPage)
+    elif fileName:
+        if not summary:
+            summary = wikipedia.translate(mysite, msg_simple_protect)
+        gen = pagegenerators.TextfilePageGenerator(fileName)
+    elif doImages:
+        if not summary:
+            summary = wikipedia.translate(mysite, msg_protect_images) % pageName
+        gen = pagegenerators.ImagesPageGenerator(wikipedia.Page(mysite, pageName))
+ 
+    if gen:
+        wikipedia.setAction(summary)
+        # We are just protecting pages, so we have no need of using a preloading page generator
+        # to actually get the text of those pages.
+        if not edit: edit = defaultProtection
+        if not move: move = defaultProtection
+        bot = ProtectionRobot(gen, summary, always, edit=edit, move=move)
+        bot.run()
+    else:
+        wikipedia.showHelp(u'protect')
+ 
+if __name__ == "__main__":
+    try:
+        main()
+    finally:
+        wikipedia.stopme()


Property changes on: trunk/pywikipedia/protect.py
___________________________________________________________________
Name: svn:eol-style
   + native





More information about the Pywikipedia-l mailing list