Here's a simple Python Flask app. It uses the Wikidot API to transfer pages between two wikis. I'd like to hear your input on the best way to refactor this code. Here are a couple of questions I have in addition to any criticisms you may have:
get_lines()
: there are two places in here where exceptions can be thrown. I want to be able to catch them independently to be able to give better feedback (see how flash()
is used).
However, now you have two types of returns for this function (and, in my opinion, that's not very Pythonic): you have a None type if there was an error and a variable if there wasn't. How should the exceptions be best handled here: at the call site or in the function?
def get_lines(admin):
try:
data = admin.pages.get_one({'site': ADMIN_SITE, 'page': SOURCE_PAGE})['content']
except:
flash('Error: unable to fetch the production-wiki page with mappings')
return
data = data.splitlines()
try:
idx = data.index(SEPERATOR)
data = data[idx+1:]
except:
flash('Error: malformed page mapping')
return
return data
What's the best way to abstract update_pictures
and update_wiki
? They're 90% the same logic.
def update_pictures():
try:
admin, prod = get_proxies()
except:
flash('Error: Unable to initialize XMLRPC connections')
return
data = get_lines(admin)
if not data:
return
for idx, line in enumerate(data):
if line.count('|') != 3:
continue
admin_page_url, admin_file_url, prod_page_url = line.split('|')
if not admin_page_url:
flash('Line {0}: Error: no admin page url'.format(idx))
return
if not admin_file_url:
flash('Line {0}: Error: no admin file url'.format(idx))
return
if not prod_page_url:
flash('Line {0}: Error: no prod page url'.format(idx))
return
try:
file_ = admin.files.get_one(ADMIN_SITE, admin_page_url, admin_file_url)
except:
flash('Line {0]: Error: unable to fetch file {1}/{2}'.format(idx, admin_page_url, admin_file_url))
return
kwargs = {'site': PROD_SITE,
'page': prod_page_url,
'file': admin_file_url,
'content': file_['content'],
'revision_comment': 'Updated by wiki_copy script'}
if file_['comment']:
kwargs['comment'] = admin_page_content['comment']
try:
prod.files.save_one(kwargs)
except:
flash('Line {0}: Error: unable to save page {1}/{2}->{3}/{2}'.format(idx, admin_page_url, admin_file_url, prod_page_url))
return
flash('Line {0}: Successful copy: {1}/{2}->{3}/{2}'.format(idx, admin_page_url, admin_file_url, prod_page_url))
def update_wiki():
try:
admin, prod = get_proxies()
except:
flash('Error: Unable to initialize XMLRPC connections')
return
data = get_lines(admin)
if not data:
return
for idx, line in enumerate(data):
if line.count('|') != 1:
continue
admin_page_url, prod_page_url = line.split('|')
if not admin_page_url:
flash('Line {0}: Error: no admin page url'.format(idx))
return
if not prod_page_url:
flash('Line {0}: Error: no prod page url'.format(idx))
return
try:
admin_page_content = admin.pages.get_one({'site': ADMIN_SITE, 'page': admin_page_url})
except:
flash('Line {0]: Error: unable to fetch page {1}'.format(idx, admin_page_url))
return
kwargs = {'site': PROD_SITE,
'page': prod_page_url,
'revision_comment': 'Updated by wiki_copy script'}
title = admin_page_content['title']
if not title:
title = prod_page_url
kwargs['title'] = title
content = admin_page_content['content']
if not content:
flash('Line {0}: Error: page {1} has no content'.format(idx, admin_page_url))
return
kwargs['content'] = content
if admin_page_content['tags']:
kwargs['tags'] = admin_page_content['tags']
try:
prod.pages.save_one(kwargs)
except:
flash('Line {0}: Error: unable to save page {1}->{2}'.format(idx, admin_page_url, prod_page_url))
return
flash('Line {0}: Successful copy: {1}->{2}'.format(idx, admin_page_url, prod_page_url))
return
I do understand that the best way to do the I/O is to do just about anything anything other than have it block the main thread and the Flask request. However, this is just a quick script (hence the use of Flask). The reason why there are two paths (one for pages, one for file attachments) is because I want to reduce the chance of timeouts.