Jump to content

User:PotatoBot/Code/2

From Wikipedia, the free encyclopedia
#!/usr/bin/python
# -*- coding: utf-8  -*-

import wikipedia as w
import time, re, pagegenerators, codecs, mysave, pickle, os
from datetime import date

# PotatoBot Task 2: Creates redirects from ISO 639 codes and ISO names to language articles;
# checks language infoboxes

tasklink = '[[w:Bots/Requests for approval/PotatoBot 2.2|Task 2]]'
rfromname = '{{R from alternative name}}'
redlist = u"""Languages with [[ISO 639-3]] codes that haven't got Wikipedia articles –
there might be articles under different names, though (%s). Date: %s.\n""" % (tasklink, mysave.fmtdate(date.today()))

def ISOredir(isopage, lang1page, lang2page, langlinks, part):
	"""Try to create a redirect, and treat various special cases. Add {{R from ISO 639}} if necessary."""
	
	# Initialise strings, show language in console window
	global exclWrongRedirs
	rfromISO = '{{R from ISO 639|%s%s}}' % (isopage.title()[8:].upper(), (part in (1, 5)) * ('|' + '%d' % part))
	w.output('* ' + isopage.title() + ' -> ' + langlinks)

	if isopage.exists():
		if isopage.isRedirectPage():
			try:
				redirtarget = isopage.getRedirectTarget()
			except:
				if not isopage.title() in exclWrongRedirs:
					w.output('  \03{yellow}invalid redirect?\03{default}')
					return '# %s: not a valid redirect?\n' % isopage.aslink()
				else:
					return ''
			if redirtarget in [lang1page] + (lang2page != None) * [lang2page]:
				# {{R from ISO 639}} present?
				redirtext = isopage.get(get_redirect=True)
				if re.search(r'\{\{\s*[Rr] from ISO 639', redirtext):
					if part not in (1, 5) or '|%d}}' % part in redirtext:
						w.output('  redirect present and okay')
						return ''
					else:
						w.output('  add {{R from ISO 639|...|part}}')
						c = redirtext.find('from ISO 639') + 15 + (part == 5)
						return mysave.savepage(isopage, redirtext[:c] + ('|%d' % part) + redirtext[c:], '2', \
							'Redirect from [[ISO 639-%s]]' % part)
				else:
					w.output('  add {{R from ISO 639|...}}')
					return mysave.savepage(isopage, redirtext + rfromISO, '2', 'Redirect from [[ISO 639]]')
			elif not isopage.title() in exclWrongRedirs:
				w.output('  \03{yellow}doesn\'t redirect to the right page?\03{default}')
				return '# %s: redirects to %s, but the ISO list has %s\n'\
					% (isopage.aslink(), isopage.getRedirectTarget().aslink(), langlinks)
			else:
				return ''
		elif not isopage.title() in exclWrongRedirs:
			w.output('  \03{yellow}not a redirect\03{default}')
			return '# %s: not a redirect\n' % isopage.aslink()
		else:
			return ''
	else:
		result = ''
		if lang1page.exists():
			if part == 3 and lang1page != lang2page:
				if lang2page.exists():
					w.output('  \03{yellow}second possible target found (%s)\03{default}' % lang2page.title())
					result = '# %s: another possible target language found, %s\n' % (isopage.aslink(), lang2page.aslink())
				else:
					w.output('  creating redirect %s' % lang2page.title())
					result = mysave.makeredir(lang2page, lang1page, '2', rfromname)
			w.output('  creating redirect %s' % isopage.title())
			return result + mysave.makeredir(isopage, lang1page, '2', rfromISO)
		elif part != 5 and lang2page.exists():
			w.output('  creating redirect(s) %s, %s' % ((part == 3) * lang1page.title(), isopage.title()))
			if part == 3:
				result = mysave.makeredir(lang1page, lang2page, '2', rfromname)
			return result + mysave.makeredir(isopage, lang2page, '2', rfromISO)
		else:
			return ''
	
def addInfobox(page, iso):
	"""Create an {{infobox language}} and add it to page."""
	# Todo: create infobox #
	# text = page.get()
	w.output('  \03{yellow}%s has no language infobox (could be added)\03{default}' % page.title())
	return '# %s ([[ISO 639:%s]]) has no language infobox (could be added)\n' % (page.aslink(), iso)
	# return mysave.savepage(page, text, BRFANo, 'Adding {{Infobox language}}')

def testdict(isopage, lang1page, lang2page, langlinks, langs = None):
	"""Cross-check dictionary against existing redirects, create missing redirects and log possible problems."""
	global redlist, exclTooMany, exclWrongboxes
	# Todo: check whether lcn here = iso3 in target page of lln #
	# Todo: check ISO 639-1 and -5 codes #
	iso = isopage.title()[8:]
	if lang1page.exists():
		finalpage = lang1page
	elif lang2page.exists():
		finalpage = lang2page
	else:
		finalpage = None
	if langs:
		if len(langs) == 2:
			if finalpage:
				if finalpage.title() == langs[1]:
					w.output('  infobox check okay')
					return ''
				elif not langs[1] in exclWrongBoxes:
					w.output('  \03{yellow}"%s" is in %s instead of %s\03{default}'\
						% (iso, langs[1], finalpage.title()))
					return '# ISO code "%s" found in [[%s]] (but should be in %s per the ISO lists)\n'\
						% (iso, langs[1], finalpage.aslink())
				else:
					return ''
			else:
				w.output('  creating redirects %s, %s, %s' %\
					(isopage.title(), lang1page.title(), lang2page.title()))
				redirto = w.Page(w.getSite(), langs[1])
				result = ''
				if lang1page != lang2page:
					result = mysave.makeredir(lang2page, redirto, '2', langs[0] * rfromname)
				return mysave.makeredir(lang1page, redirto, '2', langs[0] * rfromname) + result +\
					mysave.makeredir(isopage, redirto, '2', '{{R from ISO 639|%s}}' % iso.upper())
		else:
			langsX = langs[1:]
			for lang in langsX:
				if lang in exclTooMany:
					langsX.remove(lang)
				else:
					langs.remove(lang)
			if len(langsX) > 0:
				w.output('  \03{yellow}ISO code found more than once\03{default}')
				return '# ISO code "%s" found more than once: in [[%s]]' % (iso, ']], [['.join(langsX)) +\
					(len(langs) > 1) * (' (already present in [[%s]])' % ']], [['.join(langs[1:])) + '\n'
			else:
				return ''
	elif finalpage:
		if not finalpage.title() in exclWrongBoxes:
			if 'Infobox language' in finalpage.templates() or 'Infobox Language' in finalpage.templates():
				msg = 'a language infobox with a wrong code?'
			elif not '#' in finalpage.title():
				return addInfobox(finalpage, iso)
			else:
				msg = 'no language infobox'
			w.output('  \03{yellow}%s has %s\03{default}' % (finalpage.title(), msg))
			return '# %s (%s) has %s\n' % (finalpage.aslink(), isopage.aslink(), msg)
		else:
			return ''
	else:
		redlist += '# %s: %s\n' % (iso, langlinks)
		w.output('  \03{purple}no target language found for %s\03{default}' % isopage.title())
		return ''

def fmtLang(rawlang):
	"""Catch linked (and possibly piped) entries, brackets and commas, etc."""
	if rawlang == '':
		return ''
	search3a = re.search(r'\[\[(.*?)[\]\|]', rawlang)
	if search3a:
		lang = search3a.group(1).strip()
	else:
		lang = rawlang.strip()
	if lang.lower().find('language') == -1 and lang != '(none)' and lang.lower() != 'undetermined':
		par = lang.find('(')
		comma = lang.find(', ')
		if comma == -1:
			comma = par - 1
		lang = (((comma > -1 and par > -1) * lang[comma+2:par])\
			+ ((comma > -1 and par == -1) * (lang[comma+2:] + ' '))\
			+ (comma > -1) * lang[:comma]\
			+ (comma <= -1) * lang\
			+ ' language'\
			+ ((par > -1 and not re.search(r'\d', lang[par:])) * (' ' + lang[par:]))).strip()
	return lang

def DABsearch(dab, isotarget):
	found, dabpage = False, w.Page(w.getSite(), dab)
	exists = dabpage.exists() and dabpage.isDisambig()
	if exists:
		if dabpage.isRedirectPage():
			found = dabpage.getRedirectTarget() == isotarget
		else:
			for link in dabpage.linkedPages():
				if mysave.resolveredir(link) == isotarget:
					found = True
					break
	return [exists * ('[[' + dab + ']]'), found]

def TLDabs(isopage):
	"""Check two/three letter disambiguation pages."""
	if isopage.exists():
		iso = isopage.title()[8:].upper()
		dabs = (iso, iso.lower(), iso + ' (disambiguation)', iso.lower() + ' (disambiguation)')
		isotarget = mysave.resolveredir(isopage)
		results = []
		for dab in dabs:
			results += DABsearch(dab, isotarget)
			if True in results[1::2]:
				break
		if True in results[1::2]:
			w.output('  dab %s okay' % iso)
			return ''
		else:
			w.output('  \03{yellow}missing link from dab %s\03{default}' % iso)
			return '# %s: %s\n' % (' '.join(results[::2]), isotarget.aslink())
	else:
		return ''

def loadTabs(file, name):
	result, first = {}, True
	with codecs.open(file, 'r', 'utf-8') as f:
		for line in f:
			if first:
				first = False
			else:
				result[line[:3]] = [s.strip() for s in line[4:].split('\t')[:-1]]
	w.output('%s entries loaded: %d' % (name, len(result)))
	return result

def main():
	global exclTooMany, exclWrongRedirs, exclWrongBoxes
	# Prepare log
	listout = ('Log for the creation of [[ISO 639-3]] redirects and checking of codes in '
	'{{tl|Infobox language}} transclusions (%s). Date: %s.\n\n' 
	'<small>If you have checked an entry in this list and found it to be correct, '
	'please add it to the [[User:PotatoBot/Excludes/Language articles|exclusion list]].</small>\n'\
		% (tasklink, mysave.fmtdate(date.today())))
	dablist = u'Three letter disambiguation pages missing ISO 639-3 code, or with a wrong ISO code (%s). Date: %s.\n' \
		% (tasklink, mysave.fmtdate(date.today()))

	# Load data from text files and excludes
	w.output('')
	SIL     = loadTabs('data/SIL_tab.txt', 'SIL')
	retired = loadTabs('data/retired.txt', 'Retired')
	for code in retired:
		if code not in SIL:
			SIL[code] = ['', '', '', '', '', retired[code][0], '']
	macro   = loadTabs('data/macro.txt',   'Macrolanguage')
	iso5    = loadTabs('data/iso5.txt',    'ISO 639-5')
	
	exclWrongRedirs = [page.title() for page in pagegenerators.LinkedPageGenerator(w.Page(w.getSite(),\
		'User:PotatoBot/Excludes/Language articles#WrongRedir'))]
	exclWrongBoxes = [page.title() for page in pagegenerators.LinkedPageGenerator(w.Page(w.getSite(),\
		'User:PotatoBot/Excludes/Language articles#WrongBox'))]
	exclTooMany = [page.title() for page in pagegenerators.LinkedPageGenerator(w.Page(w.getSite(),\
		'User:PotatoBot/Excludes/Language articles#TooMany'))]
	w.output('\nExcludes loaded: %d wrong redir(s), %d wrong infobox(es), %d multiple codes'\
		% (len(exclWrongRedirs), len(exclWrongBoxes), len(exclTooMany)))

	# Create/load dictionary of ISO codes in language infoboxes
	if os.path.isfile('data/isodict.pck'):
		f = open('data/isodict.pck', 'r')
		dict = pickle.load(f)
	else:
		dict = {}
		params = ['iso3'] + ['lc%d' % (n+1) for n in range(99)]
		for page in pagegenerators.ReferringPageGenerator(w.Page(w.getSite(), 'Template:Infobox language'),
					onlyTemplateInclusion=True):
				if page.namespace() == 0:
					w.output('* page %s' % (page.aslink()))
					for template in page.templatesWithParams():
						if template[0].lower() == 'infobox language':
							for param in template[1]:
								value = param.partition('=')
								code = value[2].strip()
								if value[0].strip() in params and not code in ['', 'none']:
									mainlang = value[0].strip() == 'iso3'
									w.output('  > code "%s" found' % code + (not mainlang) * ' (dialect)')
									if code not in dict:
										dict[code] = [mainlang]
									if (dict[code][0] == mainlang) or (page.title() in dict[code]):
										if page.title() in dict[code]:
											dict[code][0] = True
										dict[code].append(page.title())
									elif mainlang:
										dict[code] = [True, page.title()]
		f = open('data/isodict.pck', 'w')
		pickle.dump(dict, f)
	
	w.output('\nLanguage infoboxes loaded: %d' % len(dict))
	
	regex1  = re.compile(r'^!(.*)\{\{\s*[Aa]nchor\\s*|\s*([a-z]{3})\s*}}')
	regex2  = re.compile(r'^!(.*)\[\[(.*)\|([a-z]{3})\]\]')
	regex3  = re.compile(r'^\|(.*?)\|\|(.*?)\|\|(.*?)\|\|(.*?)\|\|(.*?)\|\|(.*?)($|\|\|)')
	
	# Create article list and run
	for a in range(97, 123):
		abclist = w.Page(w.getSite(), 'ISO 639:'+chr(a))
		lines = abclist.get().splitlines(True)
		
		# Include Ethnologue and SIL data, update tables
		lineNo, alphaerror = 1, False
		for i in range(26 ** 2):
			code = chr(a) + chr(i / 26 + 97) + chr(i % 26 + 97)
			while lineNo < len(lines) - 1 and (lines[lineNo-1][:2] not in ('|-', '|}') or '...' in lines[lineNo]):
				lineNo += 1
			if '{{anchor|%s}}' % code not in lines[lineNo] and code in SIL:
				lines[lineNo-1:lineNo-1] = ['|-\n', '!%s {{anchor|%s}}\n' % (code, code), 10 * '| |' + '|\n']
			if lineNo < len(lines) - 1 and '{{anchor|%s}}' % code in lines[lineNo]:
				if code in SIL:
					if '[[' not in lines[lineNo] and code not in ('mis', 'mul', 'und', 'zxx'):
						lines[lineNo] = '![[%s|%s]] {{anchor|%s}}\n' % (fmtLang(SIL[code][5]), code, code)
					search = regex3.search(lines[lineNo+1])
					if search.group(6).strip() == '':
						lines[lineNo+1] = lines[lineNo+1][:search.start(6)] + SIL[code][5] + lines[lineNo+1][search.end(6):]
						search = regex3.search(lines[lineNo+1])
					lines[lineNo+1] = lines[lineNo+1][:search.start(1)] + (SIL[code][2] or ' ') + \
						lines[lineNo+1][search.end(1):search.start(2)] + (SIL[code][0] or ' ')+ \
						lines[lineNo+1][search.end(2):]
					if code not in retired:
						search = regex3.search(lines[lineNo+1])
						lines[lineNo+1] = lines[lineNo+1][:search.start(3)] + SIL[code][3] + '/' + SIL[code][4] + \
							lines[lineNo+1][search.end(3):]
					elif '!(' not in lines[lineNo]:
						b1 = lines[lineNo].find('[[')
						b2 = lines[lineNo].find(']]') + 2
						lines[lineNo] = '!(' + lines[lineNo][b1:b2] + ')' + lines[lineNo][b2:]
					search = regex3.search(lines[lineNo+1])
					scopetype = lines[lineNo+1][search.start(3):search.end(3)]
					lines[lineNo-1] = '|-' + (len(scopetype) == 3 and scopetype != 'I/L') * \
						('{{ISO 639-3 style|%s|%s}}' % (scopetype[0:1], scopetype[2:3])) + '\n'
				lineNo += 1
		
		while lineNo < len(lines) - 1:
			lineNo += 1
			if '{{anchor|' in lines[lineNo].lower():
				alphaerror = True
		text = ''.join(lines)
		if alphaerror:
			lines = abclist.get().splitlines(True)
			w.output('  \03{yellow}%s not sorted alphabetically: using old table\03{default}' % abclist.title())
			listout += u'# List %s does not seem to be sorted alphabetically – using old table\n' % abclist.aslink()
		if text != abclist.get():
			listout += mysave.savepage(abclist, text, '2.2', 'Update, wikilinks')

		# Create iso, lang1, lang2
		for n in range(len(lines)):
			iso, iso1, lang1, lang2 = '', '', '', ''
			search1 = regex1.search(lines[n])
			search2 = regex2.search(lines[n])
			if search1:
				iso = search1.group(2)
			elif search2:
				iso = search2.group(3)
			if lines[n][0:1] == '!' and n < len(lines)-1:
				search3 = regex3.search(lines[n+1])
				if search3:
					lang2 = fmtLang(search3.group(6))
					iso1 = search3.group(1).strip()
			if search2:
				lang1 = search2.group(2).strip()
				if not lang2:
					lang2 = lang1
			else:
				p = lang2.find('(')
				if p > 0:
					lang1 = (lang2[p+1:-1] + ' ' + lang2[:p-1]).strip()
				else:
					lang1 = lang2
				
			# If a language is found, create redirects; log problems
			if iso != '' and lang1 != '' and lang2 != '':
				w.output('')
				isopage = w.Page(w.getSite(), 'ISO 639:' + iso)
				iso1page = w.Page(w.getSite(), 'ISO 639:' + iso1)
				lang1page = mysave.resolveredir(w.Page(w.getSite(), lang1))
				lang2page = mysave.resolveredir(w.Page(w.getSite(), lang2))
				if lang1page.exists() and lang1page.isDisambig():
					lang1page = lang2page
				if lang2page.exists() and lang2page.isDisambig():
					lang2page = lang1page
				langlinks = lang1page.aslink() + (lang1page.title() != lang2page.title()) * (' / ' + lang2page.aslink())
				if not (lang2page.exists() and lang2page.isDisambig()):
					listout += ISOredir(isopage, lang1page, lang2page, langlinks, 3)
					dablist += TLDabs(isopage)
					if iso1 != '':
						listout += ISOredir(iso1page, lang1page, lang2page, langlinks, 1)
						dablist += TLDabs(iso1page)
					listout += testdict(isopage, lang1page, lang2page, langlinks, dict.pop(iso, None))
				else:
					w.output('  \03{red}only disambigs found for code %s\03{default}' % iso)
					listout += '# Only disambiguation pages found for code %s\n' % iso
			elif lines[n][0:1] == '!':
				w.output('  \03{red}could not parse "%s" in %s\03{default}' % (lines[n].strip(), abclist.aslink()))
				listout += '# Could not parse line "<nowiki>%s</nowiki>" in %s\n' % (lines[n].strip(), abclist.aslink())

	# ISO 639-5 redirects
	for code in iso5:
		iso5page = w.Page(w.getSite(), 'ISO 639:' + code)
		listout += ISOredir(iso5page, mysave.resolveredir(w.Page(w.getSite(), iso5[code][0])), None, iso5[code][0], 5)
		dablist += TLDabs(iso5page)

	# Log invalid codes
	for item in dict:
		listout += '# Code "%s" in [[%s]] not listed\n' % (item, ']], [['.join(dict[item][1:]))

	# Output logs
	w.output('')
	mysave.savepage(w.Page(w.getSite(), 'User:PotatoBot/Lists/ISO 639 log'), listout, '2.2', 'Creating [[ISO 639-3]] log')
	mysave.savepage(w.Page(w.getSite(), 'User:PotatoBot/Lists/ISO 639 language articles missing'), redlist, '2.2',
		'Creating list of missing [[ISO 639-3]] language articles')
	mysave.savepage(w.Page(w.getSite(), 'User:PotatoBot/Lists/Dabs without ISO 639 codes'), dablist, '2.2',
		'Creating list of missing [[ISO 639-3]] codes in disambiguation pages')


if __name__ == "__main__":
	try:
		main()
	finally:
		w.stopme()

mysave.py

[edit]
#!/usr/bin/python
# -*- coding: utf-8  -*-

import pywikibot as w
import re

# Code for saving redirects and other pages

def savepage(page, text, BRFANo, summary = '', minor = False):
	"""Save text to a page and log exceptions."""
	if summary != '':
		w.setAction(summary + '. See [[Wikipedia:Bots/Requests for approval/PotatoBot ' + BRFANo + '|approval]]. Report errors and suggestions at [[User talk:PotatoBot]].')
	try:
		if not '#' in page.title():
			page.put(text, minorEdit = minor)
			w.output('  \03{green}saving %s -> \03{gray}%s\03{default}' % (page.title(), text))
			return ''
		else:
			w.output('  \03{red}cannot save %s because it is a section\03{default}' % page.title())
			return '# %s: this is a secion title' % page.title(aslink=True)
	except w.LockedPage:
		w.output('  \03{red}cannot save %s because it is locked\03{default}' % page.title())
		return '# %s: page was locked\n' % page.title(aslink=True)
	except w.EditConflict:
		w.output('  \03{red}cannot save %s because of edit conflict\03{default}' % page.title())
		return '# %s: edit conflict occurred\n' % page.title(aslink=True)
	except w.SpamfilterError, error:
		w.output('  \03{red}cannot save %s because of spam blacklist entry %s\03{default}' % (page.title(), error.url))
		return '# %s: spam blacklist entry\n' % page.title(aslink=True)
	except:
		w.output('  \03{red}unknown error on saving %s\03{default}' % page.title())
		return '# %s: unknown error occurred\n' % page.title(aslink=True)

def resolveredir(page):
	"""Return target if input is a redirect, else return input."""
	try:
		if page.isRedirectPage():
			try:
				w.output('  \03{gray}resolving redir %s to %s\03{default}'\
					% (page.title(), page.getRedirectTarget().title()))
				return page.getRedirectTarget()
			except:
				w.output('  \03{yellow}target %s is a broken redir\03{default}' % page.title())
				return w.Page(w.getSite(), page.title() + ' (broken redirect)')
		else:
			return page
	except:
		w.output('  \03{yellow}target %s is a bad link\03{default}' % page.title())
		return w.Page(w.getSite(), page.title() + ' (bad link)') # workaround for wikipedia.py breaking wikiasite: links

def makeredir(redirpage, page, BRFANo, templates = ''):
	"""Create a redirect and log existing page that isn't a redirect to the desired article."""
	page = resolveredir(page)
	if redirpage.exists():
		comment = ''
		if redirpage.isDisambig():
			comment = ' (disambiguation)'
			dab = redirpage
		if redirpage.isRedirectPage():
			try:
				if redirpage.getRedirectTarget().title() == page.title() or \
						redirpage.getRedirectTarget().sectionFreeTitle() == page.title():
					# Already a redir to the desired article
					return ''
				elif redirpage.getRedirectTarget().isDisambig():
					comment = ' (redirect to disambiguation)'
					dab = redirpage.getRedirectTarget()
				else:
					comment = ' (redirect)'
			except:
				comment = ' (broken redir)'
		if 'disambiguation' in comment and page in [resolveredir(p) for p in dab.linkedPages()]:
			w.output('  link to %s already on dab page %s' % (page.title(), redirpage.title()))
			return ''
		elif redirpage.title() != page.title():
			w.output('  \03{yellow}redir to %s failed, page %s already exists\03{default}' % (page.title(), redirpage.title()))
			return '# %s: redirecting to %s failed, page already exists%s\n' % (redirpage.title(aslink=True), page.title(aslink=True), comment)
		else:
			return ''
	# Else create redirect, or write page name to list if an error occurs
	else:
		return savepage(redirpage, '#REDIRECT %s %s' % (page.title(aslink=True), templates), BRFANo, 'Redirect to ' + page.title(aslink=True))

def findATCs(page, includeVet = True):
	"""Look for ATC codes in infoboxes."""
	ATCvet, prefix, suffix, supp = False, '', '', ''
	ATCvetpos, prefixpos, suffixpos, supppos = -1, -1, -1, -1
	templatenames = ('Drugbox', 'Chembox Identifiers')
	templates = page.templatesWithParams()
	for tuple in templates:
		if tuple[0] in templatenames:
			idx = templatenames.index(tuple[0])
			templatepos = templates.index(tuple)
			for param in tuple[1]:
				value = param.partition('=')
				if value[0].strip() == 'ATCvet':
					ATCvet = value[2].strip() == 'yes' and includeVet
					ATCvetpos = tuple[1].index(param)
				elif value[0].strip() == ('ATC_prefix', 'ATCCode_prefix')[idx] and value[2].strip().lower != 'none':
					prefix = value[2].strip()
					prefixpos = tuple[1].index(param)
				elif value[0].strip() == ('ATC_suffix', 'ATCCode_suffix')[idx]:
					suffix = value[2].strip()
					suffixpos = tuple[1].index(param)
				elif value[0].strip() == ('ATC_supplemental', 'ATC_Supplemental')[idx]:
					supp = value[2].strip()
					supppos = tuple[1].index(param)
	codes = (prefix != '') * [(ATCvet*'Q' + prefix + suffix)]
	for tupleSupp in page.templatesWithParams(supp):
		if tupleSupp[0] in ['ATC', 'ATCvet']:
			codes.append((tupleSupp[0] == 'ATCvet')*'Q' + tupleSupp[1][0] + tupleSupp[1][1])
	return (codes, ATCvetpos, prefixpos, suffixpos, supppos)

def addTemplateParam(page, newtemplates, BRFANo, summary = 'Updating template', minor = False):
	text = page.get()
	oldtemplates = page.templatesWithParams()
	pointer = 0
	for i in range(len(oldtemplates)):
		search1 = re.compile(r'\{\{\s*(%s|%s)%s\s*\|' % (oldtemplates[i][0][0].upper(), oldtemplates[i][0][0].lower(),\
			oldtemplates[i][0].replace(' ', '( |_)'))).search(text, pointer)
		if search1:
			pointer = end() - 1
		if newtemplates[i] != oldtemplates[i]:
			if newtemplates[i][0].strip() == oldtemplates[i][0].strip():
				for j in range(len(oldtemplates[i][1])):
					oldparam = oldtemplates[i][1][j].partition('=')
					newparam = newtemplates[i][1][j].partition('=')
					# Todo: unnamed params #
					if newparam[0] == oldparam[0]:
						span = re.compile(r'\|\s*%s\s*=\s*([^|}\s]*)\s*(}|\|)' % oldparam[0]).\
							search(text, pointer).span(1)
						pointer = span(1)
						if newparam[2].strip() != oldparam[2].strip():
							text = text[:span(0)] + newparam[2] + text[span(1):]
					else:
						text = text[:] + newtemplates[i][1][j] + text[:]
						pointer = len(text[:] + newtemplates[i][1][j])
			else:
				w.output('\03{yellow}template list does not match page %s: %s vs. %s\03{default}' % \
					(page.title(), newtemplates[i][0].strip(), oldtemplates[i][0].strip()))
				return '# %s: template list did not match templates on page' % page.title(aslink=True)
	if text != page.get():
		return savepage(page, text, BRFANo, summary, minor)
	else:
		return ''

def fmtdate(date):
	"""Format date in English w style."""
	return '%d %s %d' % (date.day, ('', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',\
		'September', 'October', 'November', 'December')[date.month], date.year)